From d1855ee400066a6db051fa3c761569499d02ac08 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 6 Jul 2021 20:51:11 +0300 Subject: [PATCH 001/303] javax.persistence.query.timeout with slowQuery repository for manual testing --- application/src/main/resources/thingsboard.yml | 2 ++ .../thingsboard/server/dao/sql/event/EventRepository.java | 6 ++++++ .../thingsboard/server/dao/sql/event/JpaBaseEventDao.java | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 05f3f1e825..5433aa2e0b 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -472,6 +472,8 @@ spring: repositories: enabled: "true" jpa: + properties: + javax.persistence.query.timeout: "${JAVAX_PERSISTENCE_QUERY_TIMEOUT:29000}" open-in-view: "false" hibernate: ddl-auto: "none" diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java index 270ab26329..5f6cf91ab3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java @@ -241,4 +241,10 @@ public interface EventRepository extends PagingAndSortingRepository implemen @Override public PageData findEvents(UUID tenantId, EntityId entityId, String eventType, TimePageLink pageLink) { + log.warn("going to run slow query"); + try { + eventRepository.slowQuery(); + } catch (Exception e) { + log.error("slowQuery" , e); + throw e; + } + log.warn("finished slow query"); return DaoUtil.toPageData( eventRepository .findEventsByTenantIdAndEntityIdAndEventType( From 3eac727557be296e0866ab80cf81e881549615e4 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 8 Jul 2021 11:03:46 +0300 Subject: [PATCH 002/303] javax.persistence.query.timeout 30 sec --- application/src/main/resources/thingsboard.yml | 2 +- .../thingsboard/server/dao/sql/event/EventRepository.java | 6 ------ .../thingsboard/server/dao/sql/event/JpaBaseEventDao.java | 8 -------- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 5433aa2e0b..b9fd354760 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -473,7 +473,7 @@ spring: enabled: "true" jpa: properties: - javax.persistence.query.timeout: "${JAVAX_PERSISTENCE_QUERY_TIMEOUT:29000}" + javax.persistence.query.timeout: "${JAVAX_PERSISTENCE_QUERY_TIMEOUT:30000}" open-in-view: "false" hibernate: ddl-auto: "none" diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java index 5f6cf91ab3..270ab26329 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java @@ -241,10 +241,4 @@ public interface EventRepository extends PagingAndSortingRepository implemen @Override public PageData findEvents(UUID tenantId, EntityId entityId, String eventType, TimePageLink pageLink) { - log.warn("going to run slow query"); - try { - eventRepository.slowQuery(); - } catch (Exception e) { - log.error("slowQuery" , e); - throw e; - } - log.warn("finished slow query"); return DaoUtil.toPageData( eventRepository .findEventsByTenantIdAndEntityIdAndEventType( From 9c0aabdcd60e6ac1e50a47376e3ed604734da983 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 8 Jul 2021 19:26:53 +0300 Subject: [PATCH 003/303] enabled long query for cleanup services stmt.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(1)); --- .../java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java | 2 ++ .../org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java | 2 ++ .../thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java | 1 + .../thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java | 2 ++ 4 files changed, 7 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java index 2249de109f..8373247fc5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java @@ -50,6 +50,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.TimeUnit; @Component @Slf4j @@ -205,6 +206,7 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao imple PreparedStatement stmt = connection.prepareStatement("call cleanup_edge_events_by_ttl(?,?)")) { stmt.setLong(1, ttl); stmt.setLong(2, 0); + stmt.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(1)); stmt.execute(); printWarnings(stmt); try (ResultSet resultSet = stmt.getResultSet()) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java index ee09bb7a90..dc1640c92e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java @@ -47,6 +47,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.TimeUnit; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @@ -267,6 +268,7 @@ public class JpaBaseEventDao extends JpaAbstractDao implemen stmt.setLong(1, otherEventsTtl); stmt.setLong(2, debugEventsTtl); stmt.setLong(3, 0); + stmt.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(1)); stmt.execute(); printWarnings(stmt); try (ResultSet resultSet = stmt.getResultSet()){ 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 eb12984753..a5eee9c0f4 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 @@ -74,6 +74,7 @@ public abstract class AbstractSqlTimeseriesDao extends BaseAbstractSqlTimeseries stmt.setObject(1, ModelConstants.NULL_UUID); stmt.setLong(2, systemTtl); stmt.setLong(3, 0); + stmt.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(1)); stmt.execute(); printWarnings(stmt); try (ResultSet resultSet = stmt.getResultSet()) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java index c23e615548..6b9078a3b8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java @@ -47,6 +47,7 @@ import java.time.format.DateTimeFormatter; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; @Component @@ -111,6 +112,7 @@ public class JpaPsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa stmt.setString(1, partitioning); stmt.setLong(2, systemTtl); stmt.setLong(3, 0); + stmt.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(1)); stmt.execute(); printWarnings(stmt); try (ResultSet resultSet = stmt.getResultSet()) { From e3d0da90be7735d8049bca1bf5c4800bb959bd23 Mon Sep 17 00:00:00 2001 From: AndrewVolosytnykhThingsboard Date: Thu, 1 Jul 2021 16:21:44 +0300 Subject: [PATCH 004/303] Implement fields validation --- .../server/controller/AdminController.java | 3 +- .../controller/EntityRelationController.java | 2 + .../controller/TelemetryController.java | 141 +++++++++++++----- .../server/common/data/ContactBased.java | 12 +- .../server/common/data/Customer.java | 8 +- .../server/common/data/DashboardInfo.java | 2 + .../server/common/data/Device.java | 4 + .../server/common/data/DeviceProfile.java | 2 + .../server/common/data/EntityView.java | 3 + .../server/common/data/OtaPackageInfo.java | 9 +- .../server/common/data/TbResource.java | 2 + .../server/common/data/TbResourceInfo.java | 2 + .../server/common/data/Tenant.java | 5 +- .../server/common/data/TenantProfile.java | 2 + .../thingsboard/server/common/data/User.java | 4 +- .../server/common/data/alarm/Alarm.java | 2 + .../server/common/data/edge/Edge.java | 5 +- .../common/data/kv/BaseAttributeKvEntry.java | 4 +- .../server/common/data/kv/BasicKvEntry.java | 3 + .../common/data/kv/StringDataEntry.java | 1 + .../common/data/relation/EntityRelation.java | 6 +- .../server/common/data/rule/RuleChain.java | 2 + .../server/common/data/rule/RuleNode.java | 3 + .../server/common/data/validation/Length.java | 38 +++++ .../common/data/widget/WidgetsBundle.java | 4 +- .../dao/service/ConstraintValidator.java | 63 ++++++++ .../server/dao/service/DataValidator.java | 45 +----- .../dao/service/StringLengthValidator.java | 41 +++++ .../add-attribute-dialog.component.html | 3 + .../add-attribute-dialog.component.ts | 2 +- .../entity/contact-based.component.ts | 8 +- .../add-device-profile-dialog.component.html | 3 + .../add-device-profile-dialog.component.ts | 2 +- .../profile/device-profile.component.html | 3 + .../profile/device-profile.component.ts | 2 +- .../profile/tenant-profile.component.html | 3 + .../profile/tenant-profile.component.ts | 2 +- .../device-wizard-dialog.component.html | 6 + .../wizard/device-wizard-dialog.component.ts | 4 +- .../resource/resources-library.component.html | 3 + .../resource/resources-library.component.ts | 23 ++- .../home/pages/asset/asset.component.html | 6 + .../home/pages/asset/asset.component.ts | 6 +- .../pages/customer/customer.component.html | 3 + .../home/pages/customer/customer.component.ts | 2 +- .../dashboard/dashboard-form.component.html | 3 + .../dashboard/dashboard-form.component.ts | 2 +- .../home/pages/device/device.component.html | 6 + .../home/pages/device/device.component.ts | 4 +- .../home/pages/edge/edge.component.html | 9 ++ .../modules/home/pages/edge/edge.component.ts | 6 +- .../entity-view/entity-view.component.html | 3 + .../entity-view/entity-view.component.ts | 4 +- .../ota-update/ota-update.component.html | 12 +- .../pages/rulechain/rulechain.component.html | 3 + .../pages/rulechain/rulechain.component.ts | 2 +- .../home/pages/tenant/tenant.component.html | 3 + .../home/pages/tenant/tenant.component.ts | 2 +- .../widget/widgets-bundle.component.html | 3 + .../pages/widget/widgets-bundle.component.ts | 2 +- .../shared/components/contact.component.html | 9 ++ ...entity-subtype-autocomplete.component.html | 3 + .../entity-subtype-autocomplete.component.ts | 15 +- .../relation-type-autocomplete.component.html | 3 + .../relation-type-autocomplete.component.ts | 2 +- .../assets/locale/locale.constant-en_US.json | 30 +++- 66 files changed, 477 insertions(+), 148 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/validation/Length.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/service/ConstraintValidator.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/service/StringLengthValidator.java diff --git a/application/src/main/java/org/thingsboard/server/controller/AdminController.java b/application/src/main/java/org/thingsboard/server/controller/AdminController.java index 5bd099d07a..2272cbeab4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AdminController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AdminController.java @@ -26,12 +26,12 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.SmsService; -import org.thingsboard.server.common.data.sms.config.TestSmsRequest; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.model.SecuritySettings; +import org.thingsboard.server.common.data.sms.config.TestSmsRequest; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; @@ -88,6 +88,7 @@ public class AdminController extends BaseController { } else if (adminSettings.getKey().equals("sms")) { smsService.updateSmsConfiguration(); } + return adminSettings; } catch (Exception e) { throw handleException(e); diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 3f072b77f0..e1f3cdf6ad 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.dao.service.ConstraintValidator; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; @@ -63,6 +64,7 @@ public class EntityRelationController extends BaseController { if (relation.getTypeGroup() == null) { relation.setTypeGroup(RelationTypeGroup.COMMON); } + ConstraintValidator.validateFields(relation); relationService.saveRelation(getTenantId(), relation); logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), 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 d311cdbfed..7ec626bcdf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -48,7 +48,6 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -73,6 +72,7 @@ import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.transport.adaptor.JsonConverter; +import org.thingsboard.server.dao.service.ConstraintValidator; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.AccessValidator; @@ -138,7 +138,11 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult getAttributeKeys( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); + try { + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -147,8 +151,12 @@ public class TelemetryController extends BaseController { public DeferredResult getAttributeKeysByScope( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr , @PathVariable("scope") String scope) throws ThingsboardException { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); + try { + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -157,9 +165,13 @@ public class TelemetryController extends BaseController { public DeferredResult getAttributes( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { - SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); + try { + SecurityUser user = getCurrentUser(); + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -169,9 +181,13 @@ public class TelemetryController extends BaseController { @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { - SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); + try { + SecurityUser user = getCurrentUser(); + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -179,8 +195,12 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult getTimeseriesKeys( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); + try { + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -190,10 +210,14 @@ public class TelemetryController extends BaseController { @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @RequestParam(name = "keys", required = false) String keysStr, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { - SecurityUser user = getCurrentUser(); + try { + SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); + } catch (Exception e) { + throw handleException(e); + } } @@ -211,15 +235,19 @@ public class TelemetryController extends BaseController { @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> { - // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted - Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); - List queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) - .collect(Collectors.toList()); - - Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); - }); + try { + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> { + // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted + Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); + List queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) + .collect(Collectors.toList()); + + Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); + }); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -227,8 +255,12 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult saveDeviceAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); + try { + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -237,8 +269,12 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityAttributesV1(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -247,8 +283,12 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityAttributesV2(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -257,8 +297,12 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetry(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody String requestBody) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveTelemetry(getTenantId(), entityId, requestBody, 0L); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveTelemetry(getTenantId(), entityId, requestBody, 0L); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -267,8 +311,12 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetryWithTTL(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @PathVariable("ttl") Long ttl, @RequestBody String requestBody) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveTelemetry(getTenantId(), entityId, requestBody, ttl); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveTelemetry(getTenantId(), entityId, requestBody, ttl); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -280,8 +328,12 @@ public class TelemetryController extends BaseController { @RequestParam(name = "startTs", required = false) Long startTs, @RequestParam(name = "endTs", required = false) Long endTs, @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); + } catch (Exception e) { + throw handleException(e); + } } private DeferredResult deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys, @@ -335,8 +387,12 @@ public class TelemetryController extends BaseController { public DeferredResult deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys") String keysStr) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); - return deleteAttributes(entityId, scope, keysStr); + try { + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); + return deleteAttributes(entityId, scope, keysStr); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -345,8 +401,12 @@ public class TelemetryController extends BaseController { public DeferredResult deleteEntityAttributes(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys") String keysStr) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return deleteAttributes(entityId, scope, keysStr); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return deleteAttributes(entityId, scope, keysStr); + } catch (Exception e) { + throw handleException(e); + } } private DeferredResult deleteAttributes(EntityId entityIdSrc, String scope, String keysStr) throws ThingsboardException { @@ -392,6 +452,7 @@ public class TelemetryController extends BaseController { } if (json.isObject()) { List attributes = extractRequestAttributes(json); + attributes.forEach(ConstraintValidator::validateFields); if (attributes.isEmpty()) { return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java b/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java index a333591e53..4a57a84b1c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java @@ -17,30 +17,36 @@ package org.thingsboard.server.common.data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.UUIDBased; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @EqualsAndHashCode(callSuper = true) public abstract class ContactBased extends SearchTextBasedWithAdditionalInfo implements HasName { - + private static final long serialVersionUID = 5047448057830660988L; + @Length(fieldName = "country") @NoXss protected String country; + @Length(fieldName = "state") @NoXss protected String state; + @Length(fieldName = "city") @NoXss protected String city; @NoXss protected String address; @NoXss protected String address2; + @Length(fieldName = "zip or postal code") @NoXss protected String zip; + @Length(fieldName = "phone") @NoXss protected String phone; @NoXss protected String email; - + public ContactBased() { super(); } @@ -48,7 +54,7 @@ public abstract class ContactBased extends SearchTextBasedW public ContactBased(I id) { super(id); } - + public ContactBased(ContactBased contact) { super(contact); this.country = contact.getCountry(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java index f6f49bb33b..a3dae9ddc9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java @@ -20,13 +20,15 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty.Access; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; public class Customer extends ContactBased implements HasTenantId { - + private static final long serialVersionUID = -1599722990298929275L; @NoXss + @Length(fieldName = "title") private String title; private TenantId tenantId; @@ -37,7 +39,7 @@ public class Customer extends ContactBased implements HasTenantId { public Customer(CustomerId id) { super(id); } - + public Customer(Customer customer) { super(customer); this.tenantId = customer.getTenantId(); @@ -51,7 +53,7 @@ public class Customer extends ContactBased implements HasTenantId { public void setTenantId(TenantId tenantId) { this.tenantId = tenantId; } - + public String getTitle() { return title; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java index cbcd213377..4671de171c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; import javax.validation.Valid; @@ -29,6 +30,7 @@ public class DashboardInfo extends SearchTextBased implements HasNa private TenantId tenantId; @NoXss + @Length(fieldName = "title") private String title; private String image; @Valid diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index 9abc619b48..35fa50ea32 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; import java.io.ByteArrayInputStream; @@ -39,10 +40,13 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen private TenantId tenantId; private CustomerId customerId; @NoXss + @Length(fieldName = "name") private String name; @NoXss + @Length(fieldName = "type") private String type; @NoXss + @Length(fieldName = "label") private String label; private DeviceProfileId deviceProfileId; private transient DeviceData deviceData; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 13c4692976..29b0a3f23a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; import javax.validation.Valid; @@ -41,6 +42,7 @@ public class DeviceProfile extends SearchTextBased implements H private TenantId tenantId; @NoXss + @Length(fieldName = "name") private String name; @NoXss private String description; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java index e8b48ee23a..7a96419600 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.objects.TelemetryEntityView; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; /** @@ -41,8 +42,10 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo private TenantId tenantId; private CustomerId customerId; @NoXss + @Length(fieldName = "name") private String name; @NoXss + @Length(fieldName = "type") private String type; private TelemetryEntityView keys; private long startTimeMs; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java index f27c90c20b..be475946cb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java @@ -19,11 +19,12 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; -import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; +import org.thingsboard.server.common.data.ota.OtaPackageType; +import org.thingsboard.server.common.data.validation.Length; @Slf4j @Data @@ -35,10 +36,14 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo implements Has private TenantId tenantId; @NoXss + @Length(fieldName = "title") private String title; private ResourceType resourceType; private String resourceKey; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java index b6adf6cf65..9146212361 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @EqualsAndHashCode(callSuper = true) @@ -27,8 +28,10 @@ public class Tenant extends ContactBased implements HasTenantId { private static final long serialVersionUID = 8057243243859922101L; + @Length(fieldName = "title") @NoXss private String title; + @Length(fieldName = "region") @NoXss private String region; private TenantProfileId tenantProfileId; @@ -40,7 +43,7 @@ public class Tenant extends ContactBased implements HasTenantId { public Tenant(TenantId id) { super(id); } - + public Tenant(Tenant tenant) { super(tenant); this.title = tenant.getTitle(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java index 05d22af09f..06597e093c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java @@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; import java.io.ByteArrayInputStream; @@ -37,6 +38,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn public class TenantProfile extends SearchTextBased implements HasName { @NoXss + @Length(fieldName = "name") private String name; @NoXss private String description; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/User.java b/common/data/src/main/java/org/thingsboard/server/common/data/User.java index 420aff71ce..a7135ea56f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/User.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/User.java @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.security.Authority; - +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @EqualsAndHashCode(callSuper = true) @@ -36,8 +36,10 @@ public class User extends SearchTextBasedWithAdditionalInfo implements H private String email; private Authority authority; @NoXss + @Length(fieldName = "firs name") private String firstName; @NoXss + @Length(fieldName = "last name") private String lastName; public User() { 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 54f7ab72f5..19fc96b1b8 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 @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.validation.Length; import java.util.List; @@ -41,6 +42,7 @@ public class Alarm extends BaseData implements HasName, HasTenantId, Ha private TenantId tenantId; private CustomerId customerId; + @Length(fieldName = "type") private String type; private EntityId originator; private AlarmSeverity severity; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java index 939bfb3648..d612fe44ea 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.common.data.edge; -import com.fasterxml.jackson.databind.JsonNode; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -28,6 +27,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.validation.Length; @EqualsAndHashCode(callSuper = true) @ToString @@ -40,8 +40,11 @@ public class Edge extends SearchTextBasedWithAdditionalInfo implements H private TenantId tenantId; private CustomerId customerId; private RuleChainId rootRuleChainId; + @Length(fieldName = "name") private String name; + @Length(fieldName = "type") private String type; + @Length(fieldName = "label") private String label; private String routingKey; private String secret; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java index d87c260898..794e3a16cc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java @@ -15,8 +15,7 @@ */ package org.thingsboard.server.common.data.kv; -import com.fasterxml.jackson.databind.JsonNode; - +import javax.validation.Valid; import java.util.Optional; /** @@ -25,6 +24,7 @@ import java.util.Optional; public class BaseAttributeKvEntry implements AttributeKvEntry { private final long lastUpdateTs; + @Valid private final KvEntry kv; public BaseAttributeKvEntry(KvEntry kv, long lastUpdateTs) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicKvEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicKvEntry.java index a04c29f82b..9c2edb6250 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicKvEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicKvEntry.java @@ -15,11 +15,14 @@ */ package org.thingsboard.server.common.data.kv; +import org.thingsboard.server.common.data.validation.Length; + import java.util.Objects; import java.util.Optional; public abstract class BasicKvEntry implements KvEntry { + @Length(fieldName = "attribute key") private final String key; protected BasicKvEntry(String key) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/StringDataEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/StringDataEntry.java index 407be7ccfa..d7e27e83d1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/StringDataEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/StringDataEntry.java @@ -21,6 +21,7 @@ import java.util.Optional; public class StringDataEntry extends BasicKvEntry { private static final long serialVersionUID = 1L; + private final String value; public StringDataEntry(String key, String value) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java index 7833acc050..f8e5930823 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java @@ -16,15 +16,12 @@ package org.thingsboard.server.common.data.relation; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.validation.Length; -import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.Serializable; @Slf4j @@ -38,6 +35,7 @@ public class EntityRelation implements Serializable { private EntityId from; private EntityId to; + @Length(fieldName = "type") private String type; private RelationTypeGroup typeGroup; private transient JsonNode additionalInfo; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java index da84f15427..0b019a7330 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @Data @@ -37,6 +38,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo im private TenantId tenantId; @NoXss + @Length(fieldName = "name") private String name; private RuleChainType type; private RuleNodeId firstRuleNodeId; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java index 6d88ad6adc..8d37473768 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.validation.Length; @Data @EqualsAndHashCode(callSuper = true) @@ -33,7 +34,9 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo impl private static final long serialVersionUID = -5656679015121235465L; private RuleChainId ruleChainId; + @Length(fieldName = "type") private String type; + @Length(fieldName = "name") private String name; private boolean debugMode; private transient JsonNode configuration; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/validation/Length.java b/common/data/src/main/java/org/thingsboard/server/common/data/validation/Length.java new file mode 100644 index 0000000000..b6c7f47f5c --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/validation/Length.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.validation; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Constraint(validatedBy = {}) +public @interface Length { + String message() default "length of {fieldName} should be equals or less than {max}"; + + String fieldName(); + + int max() default 255; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java index df09f75922..7b4b172ace 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java @@ -19,10 +19,9 @@ import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetsBundleId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; -import java.util.Arrays; - public class WidgetsBundle extends SearchTextBased implements HasTenantId { private static final long serialVersionUID = -7627368878362410489L; @@ -31,6 +30,7 @@ public class WidgetsBundle extends SearchTextBased implements H @NoXss private String alias; @NoXss + @Length(fieldName = "title") private String title; private String image; @NoXss diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/ConstraintValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/ConstraintValidator.java new file mode 100644 index 0000000000..30ea042b0a --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/service/ConstraintValidator.java @@ -0,0 +1,63 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.service; + +import lombok.extern.slf4j.Slf4j; +import org.hibernate.validator.HibernateValidator; +import org.hibernate.validator.HibernateValidatorConfiguration; +import org.hibernate.validator.cfg.ConstraintMapping; +import org.thingsboard.server.common.data.validation.Length; +import org.thingsboard.server.common.data.validation.NoXss; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.ValidationException; +import javax.validation.Validator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +public class ConstraintValidator { + + private static Validator fieldsValidator; + + static { + initializeValidators(); + } + + public static void validateFields(Object data) { + Set> constraintsViolations = fieldsValidator.validate(data); + List validationErrors = constraintsViolations.stream() + .map(ConstraintViolation::getMessage) + .distinct() + .collect(Collectors.toList()); + if (!validationErrors.isEmpty()) { + throw new ValidationException("Validation error: " + String.join(", ", validationErrors)); + } + } + + private static void initializeValidators() { + HibernateValidatorConfiguration validatorConfiguration = Validation.byProvider(HibernateValidator.class).configure(); + + ConstraintMapping constraintMapping = validatorConfiguration.createConstraintMapping(); + constraintMapping.constraintDefinition(NoXss.class).validatedBy(NoXssValidator.class); + constraintMapping.constraintDefinition(Length.class).validatedBy(StringLengthValidator.class); + validatorConfiguration.addMapping(constraintMapping); + + fieldsValidator = validatorConfiguration.buildValidatorFactory().getValidator(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java index e630624ed4..a0a7a3be2f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java @@ -17,51 +17,32 @@ package org.thingsboard.server.dao.service; import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; -import org.hibernate.validator.HibernateValidator; -import org.hibernate.validator.HibernateValidatorConfiguration; -import org.hibernate.validator.cfg.ConstraintMapping; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; -import org.thingsboard.server.common.data.validation.NoXss; import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityWithDataDao; import org.thingsboard.server.dao.exception.DataValidationException; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.Set; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; @Slf4j public abstract class DataValidator> { private static final Pattern EMAIL_PATTERN = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE); - private static Validator fieldsValidator; - - static { - initializeFieldsValidator(); - } - public void validate(D data, Function tenantIdFunction) { try { if (data == null) { throw new DataValidationException("Data object can't be null!"); } - List validationErrors = validateFields(data); - if (!validationErrors.isEmpty()) { - throw new IllegalArgumentException("Validation error: " + String.join(", ", validationErrors)); - } + ConstraintValidator.validateFields(data); TenantId tenantId = tenantIdFunction.apply(data); validateDataImpl(tenantId, data); @@ -104,14 +85,6 @@ public abstract class DataValidator> { return emailMatcher.matches(); } - private List validateFields(D data) { - Set> constraintsViolations = fieldsValidator.validate(data); - return constraintsViolations.stream() - .map(ConstraintViolation::getMessage) - .distinct() - .collect(Collectors.toList()); - } - protected void validateNumberOfEntitiesPerTenant(TenantId tenantId, TenantEntityDao tenantEntityDao, long maxEntities, @@ -126,10 +99,10 @@ public abstract class DataValidator> { } protected void validateMaxSumDataSizePerTenant(TenantId tenantId, - TenantEntityWithDataDao dataDao, - long maxSumDataSize, - long currentDataSize, - EntityType entityType) { + TenantEntityWithDataDao dataDao, + long maxSumDataSize, + long currentDataSize, + EntityType entityType) { if (maxSumDataSize > 0) { if (dataDao.sumDataSizeByTenantId(tenantId) + currentDataSize > maxSumDataSize) { throw new DataValidationException(String.format("Failed to create the %s, files size limit is exhausted %d bytes!", @@ -156,12 +129,4 @@ public abstract class DataValidator> { } } - private static void initializeFieldsValidator() { - HibernateValidatorConfiguration validatorConfiguration = Validation.byProvider(HibernateValidator.class).configure(); - ConstraintMapping constraintMapping = validatorConfiguration.createConstraintMapping(); - constraintMapping.constraintDefinition(NoXss.class).validatedBy(NoXssValidator.class); - validatorConfiguration.addMapping(constraintMapping); - - fieldsValidator = validatorConfiguration.buildValidatorFactory().getValidator(); - } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/StringLengthValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/StringLengthValidator.java new file mode 100644 index 0000000000..1efa0192e0 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/service/StringLengthValidator.java @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.service; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.validation.Length; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +@Slf4j +public class StringLengthValidator implements ConstraintValidator { + private int max; + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (StringUtils.isEmpty(value)) { + return true; + } + return value.trim().length() <= max; + } + + @Override + public void initialize(Length constraintAnnotation) { + this.max = constraintAnnotation.max(); + } +} diff --git a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html index 923589ed39..f64b63fe9f 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html @@ -36,6 +36,9 @@ {{ 'attribute.key-required' | translate }} + + {{ 'attribute.key-max-length' | translate }} + > exten buildForm(entity: T): FormGroup { const entityForm = this.buildEntityForm(entity); - entityForm.addControl('country', this.fb.control(entity ? entity.country : '', [])); - entityForm.addControl('city', this.fb.control(entity ? entity.city : '', [])); - entityForm.addControl('state', this.fb.control(entity ? entity.state : '', [])); + entityForm.addControl('country', this.fb.control(entity ? entity.country : '', [Validators.maxLength(255)])); + entityForm.addControl('city', this.fb.control(entity ? entity.city : '', [Validators.maxLength(255)])); + entityForm.addControl('state', this.fb.control(entity ? entity.state : '', [Validators.maxLength(255)])); entityForm.addControl('zip', this.fb.control(entity ? entity.zip : '', this.zipValidators(entity ? entity.country : '') )); entityForm.addControl('address', this.fb.control(entity ? entity.address : '', [])); entityForm.addControl('address2', this.fb.control(entity ? entity.address2 : '', [])); - entityForm.addControl('phone', this.fb.control(entity ? entity.phone : '', [])); + entityForm.addControl('phone', this.fb.control(entity ? entity.phone : '', [Validators.maxLength(255)])); entityForm.addControl('email', this.fb.control(entity ? entity.email : '', [Validators.email])); return entityForm; } diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html index b91613955d..23fdf04cde 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html @@ -41,6 +41,9 @@ {{ 'device-profile.name-required' | translate }} + + {{ 'device-profile.name-max-length' | translate }} + {{ 'device-profile.name-required' | translate }} + + {{ 'device-profile.name-max-length' | translate }} + { }; const form = this.fb.group( { - name: [entity ? entity.name : '', [Validators.required]], + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], type: [entity ? entity.type : null, [Validators.required]], image: [entity ? entity.image : null], transportType: [entity ? entity.transportType : null, [Validators.required]], diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html index e1dd51d1cd..e5a3a54293 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html @@ -48,6 +48,9 @@ {{ 'tenant-profile.name-required' | translate }} + + {{ 'tenant-profile.name-max-length' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts index afdb3eafc1..b5f5be3c9c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts @@ -58,7 +58,7 @@ export class TenantProfileComponent extends EntityComponent { buildForm(entity: TenantProfile): FormGroup { return this.fb.group( { - name: [entity ? entity.name : '', [Validators.required]], + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], isolatedTbCore: [entity ? entity.isolatedTbCore : false, []], isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], profileData: [entity && !this.isAdd ? entity.profileData : { diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index 46e83a740e..ae0be158d5 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -44,10 +44,16 @@ {{ 'device.name-required' | translate }} + + {{ 'device.name-max-length' | translate }} + device.label + + {{ 'device.label-max-length' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 68e82fc7e1..bd6b060aab 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -105,8 +105,8 @@ export class DeviceWizardDialogComponent extends private fb: FormBuilder) { super(store, router, dialogRef); this.deviceWizardFormGroup = this.fb.group({ - name: ['', Validators.required], - label: [''], + name: ['', [Validators.required, Validators.maxLength(255)]], + label: ['', Validators.maxLength(255)], gateway: [false], overwriteActivityTime: [false], addProfileType: [0], diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.html b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.html index 1f33d63776..ff2f8a1085 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.html @@ -56,6 +56,9 @@ {{ 'resource.title-required' | translate }} + + {{ 'resource.title-max-length' | translate }} + impleme super.ngOnInit(); this.entityForm.get('resourceType').valueChanges.pipe( startWith(ResourceType.LWM2M_MODEL), - pairwise(), + filter(() => this.isAdd), takeUntil(this.destroy$) - ).subscribe(([previousType, type]) => { - if (previousType === this.resourceType.LWM2M_MODEL) { - this.entityForm.get('title').setValidators(Validators.required); - this.entityForm.get('title').updateValueAndValidity({emitEvent: false}); - } + ).subscribe((type) => { if (type === this.resourceType.LWM2M_MODEL) { - this.entityForm.get('title').clearValidators(); - this.entityForm.get('title').updateValueAndValidity({emitEvent: false}); + this.entityForm.get('title').disable({emitEvent: false}); + this.entityForm.patchValue({title: ''}, {emitEvent: false}); + } else { + this.entityForm.get('title').enable({emitEvent: false}) } this.entityForm.patchValue({ data: null, @@ -91,11 +89,8 @@ export class ResourcesLibraryComponent extends EntityComponent impleme buildForm(entity: Resource): FormGroup { const form = this.fb.group( { - title: [entity ? entity.title : '', []], - resourceType: [{ - value: entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL, - disabled: !this.isAdd - }, [Validators.required]], + title: [entity ? entity.title : "", [Validators.required, Validators.maxLength(255)]], + resourceType: [entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL, [Validators.required]], fileName: [entity ? entity.fileName : null, [Validators.required]], } ); diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset.component.html b/ui-ngx/src/app/modules/home/pages/asset/asset.component.html index 66b9a152c7..8d786051a7 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset.component.html +++ b/ui-ngx/src/app/modules/home/pages/asset/asset.component.html @@ -76,6 +76,9 @@ {{ 'asset.name-required' | translate }} + + {{ 'asset.name-max-length' | translate }} + asset.label + + {{ 'asset.label-max-length' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset.component.ts b/ui-ngx/src/app/modules/home/pages/asset/asset.component.ts index 2ec441c2d3..54279e309c 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset.component.ts +++ b/ui-ngx/src/app/modules/home/pages/asset/asset.component.ts @@ -65,9 +65,9 @@ export class AssetComponent extends EntityComponent { buildForm(entity: AssetInfo): FormGroup { return this.fb.group( { - name: [entity ? entity.name : '', [Validators.required]], - type: [entity ? entity.type : null, [Validators.required]], - label: [entity ? entity.label : ''], + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], + type: [entity ? entity.type : null, [Validators.required, Validators.maxLength(255)]], + label: [entity ? entity.label : '', Validators.maxLength(255)], additionalInfo: this.fb.group( { description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer.component.html b/ui-ngx/src/app/modules/home/pages/customer/customer.component.html index 5077950a59..28fc994477 100644 --- a/ui-ngx/src/app/modules/home/pages/customer/customer.component.html +++ b/ui-ngx/src/app/modules/home/pages/customer/customer.component.html @@ -73,6 +73,9 @@ {{ 'customer.title-required' | translate }} + + {{ 'customer.title-max-length' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer.component.ts b/ui-ngx/src/app/modules/home/pages/customer/customer.component.ts index 20e49d118b..a479f8cd22 100644 --- a/ui-ngx/src/app/modules/home/pages/customer/customer.component.ts +++ b/ui-ngx/src/app/modules/home/pages/customer/customer.component.ts @@ -57,7 +57,7 @@ export class CustomerComponent extends ContactBasedComponent { buildEntityForm(entity: Customer): FormGroup { return this.fb.group( { - title: [entity ? entity.title : '', [Validators.required]], + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], additionalInfo: this.fb.group( { description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html index ca7512d7ec..a26921851d 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html @@ -104,6 +104,9 @@ {{ 'dashboard.title-required' | translate }} + + {{ 'dashboard.title-max-length' | translate }} + { this.updateFields(entity); return this.fb.group( { - title: [entity ? entity.title : '', [Validators.required]], + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], image: [entity ? entity.image : null], configuration: this.fb.group( { diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index b95dbb6584..1187a34f5d 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -89,6 +89,9 @@ {{ 'device.name-required' | translate }} + + {{ 'device.name-max-length' | translate }} + device.label + + {{ 'device.label-max-length' | translate }} + { buildForm(entity: DeviceInfo): FormGroup { const form = this.fb.group( { - name: [entity ? entity.name : '', [Validators.required]], + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]], firmwareId: [entity ? entity.firmwareId : null], softwareId: [entity ? entity.softwareId : null], - label: [entity ? entity.label : ''], + label: [entity ? entity.label : '', [Validators.maxLength(255)]], deviceData: [entity ? entity.deviceData : null, [Validators.required]], additionalInfo: this.fb.group( { diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge.component.html b/ui-ngx/src/app/modules/home/pages/edge/edge.component.html index 6ae548acb2..380ca09e93 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge.component.html +++ b/ui-ngx/src/app/modules/home/pages/edge/edge.component.html @@ -126,6 +126,9 @@ {{ 'edge.name-required' | translate }} + + {{ 'edge.name-max-length' | translate }} + {{ 'edge.edge-license-key-required' | translate }} + + {{ 'edge.type-max-length' | translate }} +
@@ -179,6 +185,9 @@ edge.label + + {{ 'edge.label-max-length' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge.component.ts b/ui-ngx/src/app/modules/home/pages/edge/edge.component.ts index 007176ce24..c1113c57ee 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge.component.ts +++ b/ui-ngx/src/app/modules/home/pages/edge/edge.component.ts @@ -69,9 +69,9 @@ export class EdgeComponent extends EntityComponent { buildForm(entity: EdgeInfo): FormGroup { const form = this.fb.group( { - name: [entity ? entity.name : '', [Validators.required]], - type: [entity?.type ? entity.type : 'default', [Validators.required]], - label: [entity ? entity.label : ''], + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], + type: [entity?.type ? entity.type : 'default', [Validators.required, Validators.maxLength(255)]], + label: [entity ? entity.label : '', Validators.maxLength(255)], cloudEndpoint: [null, [Validators.required]], edgeLicenseKey: ['', [Validators.required]], routingKey: this.fb.control({value: entity ? entity.routingKey : null, disabled: true}), diff --git a/ui-ngx/src/app/modules/home/pages/entity-view/entity-view.component.html b/ui-ngx/src/app/modules/home/pages/entity-view/entity-view.component.html index 5ce3b05569..2b3e823327 100644 --- a/ui-ngx/src/app/modules/home/pages/entity-view/entity-view.component.html +++ b/ui-ngx/src/app/modules/home/pages/entity-view/entity-view.component.html @@ -76,6 +76,9 @@ {{ 'entity-view.name-required' | translate }} + + {{ 'entity-view.name-max-length' | translate }} + { buildForm(entity: EntityViewInfo): FormGroup { return this.fb.group( { - name: [entity ? entity.name : '', [Validators.required]], - type: [entity ? entity.type : null, [Validators.required]], + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], + type: [entity ? entity.type : null, Validators.required], entityId: [entity ? entity.entityId : null, [Validators.required]], startTimeMs: [entity ? entity.startTimeMs : null], endTimeMs: [entity ? entity.endTimeMs : null], diff --git a/ui-ngx/src/app/modules/home/pages/ota-update/ota-update.component.html b/ui-ngx/src/app/modules/home/pages/ota-update/ota-update.component.html index be3a2ead31..78559429ae 100644 --- a/ui-ngx/src/app/modules/home/pages/ota-update/ota-update.component.html +++ b/ui-ngx/src/app/modules/home/pages/ota-update/ota-update.component.html @@ -65,6 +65,9 @@ {{ 'ota-update.title-required' | translate }} + + {{ 'ota-update.title-max-length' | translate }} + ota-update.version @@ -72,6 +75,9 @@ {{ 'ota-update.version-required' | translate }} + + {{ 'ota-update.version-max-length' | translate }} +
+ fxLayout.xs="column" fxLayout.md="column" + *ngIf="!(isAdd && this.entityForm.get('generateChecksum').value)"> ota-update.checksum-algorithm @@ -149,7 +156,8 @@ - + ota-update.direct-url-required diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.html index 66d5d6d74c..a93fac9beb 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.html @@ -84,6 +84,9 @@ {{ 'rulechain.name-required' | translate }} + + {{ 'rulechain.name-max-length' | translate }} + {{ 'rulechain.debug-mode' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.ts index 3d8eae1e7a..e7e7d80df1 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.ts @@ -57,7 +57,7 @@ export class RuleChainComponent extends EntityComponent { buildForm(entity: RuleChain): FormGroup { return this.fb.group( { - name: [entity ? entity.name : '', [Validators.required]], + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], debugMode: [entity ? entity.debugMode : false], additionalInfo: this.fb.group( { diff --git a/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.html b/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.html index eff1ec7bf3..498e1f5eaf 100644 --- a/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.html +++ b/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.html @@ -48,6 +48,9 @@ {{ 'tenant.title-required' | translate }} + + {{ 'tenant.title-max-length' | translate }} + { buildEntityForm(entity: TenantInfo): FormGroup { return this.fb.group( { - title: [entity ? entity.title : '', [Validators.required]], + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], tenantProfileId: [entity ? entity.tenantProfileId : null, [Validators.required]], additionalInfo: this.fb.group( { diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html index 88fde0e428..6f553a90dc 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html @@ -44,6 +44,9 @@ {{ 'widgets-bundle.title-required' | translate }} + + {{ 'widgets-bundle.title-max-length' | translate }} + { buildForm(entity: WidgetsBundle): FormGroup { return this.fb.group( { - title: [entity ? entity.title : '', [Validators.required]], + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], image: [entity ? entity.image : ''], description: [entity ? entity.description : '', Validators.maxLength(255)] } diff --git a/ui-ngx/src/app/shared/components/contact.component.html b/ui-ngx/src/app/shared/components/contact.component.html index 678232b1cd..e0c09e8ebe 100644 --- a/ui-ngx/src/app/shared/components/contact.component.html +++ b/ui-ngx/src/app/shared/components/contact.component.html @@ -28,10 +28,16 @@ contact.city + + {{ 'contact.city-max-length' | translate }} + contact.state + + {{ 'contact.state-max-length' | translate }} + contact.postal-code @@ -52,6 +58,9 @@ contact.phone + + {{ 'contact.phone-max-length' | translate }} + contact.email diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.html b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.html index 245a1f2478..69e2a830c7 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.html @@ -40,4 +40,7 @@ {{ entitySubtypeRequiredText | translate }} + + {{ entitySubtypeMaxLength | translate }} + diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts index fa0bcd3810..8a31ea71c6 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts @@ -15,7 +15,7 @@ /// import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Observable, of, Subscription, throwError } from 'rxjs'; import { catchError, @@ -58,9 +58,11 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, entityType: EntityType; private requiredValue: boolean; + get required(): boolean { return this.requiredValue; } + @Input() set required(value: boolean) { this.requiredValue = coerceBooleanProperty(value); @@ -74,6 +76,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, selectEntitySubtypeText: string; entitySubtypeText: string; entitySubtypeRequiredText: string; + entitySubtypeMaxLength: string; filteredSubTypes: Observable>; @@ -96,7 +99,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, private entityViewService: EntityViewService, private fb: FormBuilder) { this.subTypeFormGroup = this.fb.group({ - subType: [null] + subType: [null, Validators.maxLength(255)] }); } @@ -114,6 +117,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, this.selectEntitySubtypeText = 'asset.select-asset-type'; this.entitySubtypeText = 'asset.asset-type'; this.entitySubtypeRequiredText = 'asset.asset-type-required'; + this.entitySubtypeMaxLength = 'asset.asset-type-max-length'; this.broadcastSubscription = this.broadcast.on('assetSaved', () => { this.subTypes = null; }); @@ -122,6 +126,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, this.selectEntitySubtypeText = 'device.select-device-type'; this.entitySubtypeText = 'device.device-type'; this.entitySubtypeRequiredText = 'device.device-type-required'; + this.entitySubtypeMaxLength = 'device.device-type-max-length'; this.broadcastSubscription = this.broadcast.on('deviceSaved', () => { this.subTypes = null; }); @@ -130,6 +135,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, this.selectEntitySubtypeText = 'edge.select-edge-type'; this.entitySubtypeText = 'edge.edge-type'; this.entitySubtypeRequiredText = 'edge.edge-type-required'; + this.entitySubtypeMaxLength = 'edge.type-max-length'; this.broadcastSubscription = this.broadcast.on('edgeSaved', () => { this.subTypes = null; }); @@ -138,6 +144,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, this.selectEntitySubtypeText = 'entity-view.select-entity-view-type'; this.entitySubtypeText = 'entity-view.entity-view-type'; this.entitySubtypeRequiredText = 'entity-view.entity-view-type-required'; + this.entitySubtypeMaxLength = 'entity-view.type-max-length' this.broadcastSubscription = this.broadcast.on('entityViewSaved', () => { this.subTypes = null; }); @@ -149,7 +156,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, debounceTime(150), distinctUntilChanged(), tap(value => { - this.updateView(value); + this.updateView(value); }), // startWith(''), map(value => value ? value : ''), @@ -203,7 +210,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, fetchSubTypes(searchText?: string, strictMatch: boolean = false): Observable> { this.searchText = searchText; return this.getSubTypes().pipe( - map(subTypes => subTypes.filter( subType => { + map(subTypes => subTypes.filter(subType => { if (strictMatch) { return searchText ? subType === searchText : false; } else { diff --git a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html index cd60473b00..b572f6b9df 100644 --- a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html @@ -39,4 +39,7 @@ {{ 'relation.relation-type-required' | translate }} + + {{ 'relation.relation-type-max-length' | translate }} + diff --git a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts index d425e90b64..4477b9b2f0 100644 --- a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts @@ -68,7 +68,7 @@ export class RelationTypeAutocompleteComponent implements ControlValueAccessor, public translate: TranslateService, private fb: FormBuilder) { this.relationTypeFormGroup = this.fb.group({ - relationType: [null, this.required ? [Validators.required] : []] + relationType: [null, this.required ? [Validators.required, Validators.maxLength(255)] : [Validators.maxLength(255)]] }); } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index c68098b8d0..7b2cc80174 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -369,6 +369,7 @@ "management": "Asset management", "view-assets": "View Assets", "add": "Add Asset", + "asset-type-max-length": "Asset type should be less than 256", "assign-to-customer": "Assign to customer", "assign-asset-to-customer": "Assign Asset(s) To Customer", "assign-asset-to-customer-text": "Please select the assets to assign to the customer", @@ -391,6 +392,8 @@ "asset-types": "Asset types", "name": "Name", "name-required": "Name is required.", + "name-max-length": "Name should be less than 256", + "label-max-length": "Label should be less than 256", "description": "Description", "type": "Type", "type-required": "Type is required.", @@ -449,6 +452,7 @@ "scope-shared": "Shared attributes", "add": "Add attribute", "key": "Key", + "key-max-length": "Key should be less than 256", "last-update-time": "Last update time", "key-required": "Attribute key is required.", "value": "Value", @@ -590,7 +594,10 @@ "address2": "Address 2", "phone": "Phone", "email": "Email", - "no-address": "No address" + "no-address": "No address", + "state-max-length": "State length should be less than 256", + "phone-max-length": "Phone number should be less than 256", + "city-max-length": "Specified city should be less than 256" }, "common": { "username": "Username", @@ -646,6 +653,7 @@ "manage-dashboards": "Manage dashboards", "title": "Title", "title-required": "Title is required.", + "title-max-length": "Title should be less than 256", "description": "Description", "details": "Details", "events": "Events", @@ -700,6 +708,7 @@ "select-widget-subtitle": "List of available widget types", "delete": "Delete dashboard", "title-required": "Title is required.", + "title-max-length": "Title should be less than 256", "description": "Description", "details": "Details", "dashboard-details": "Dashboard details", @@ -886,6 +895,7 @@ "management": "Device management", "view-devices": "View Devices", "device-alias": "Device alias", + "device-type-max-length": "Device type should be less than 256", "aliases": "Device aliases", "no-alias-matching": "'{{alias}}' not found.", "no-aliases-found": "No aliases found.", @@ -998,6 +1008,8 @@ "device-types": "Device types", "name": "Name", "name-required": "Name is required.", + "name-max-length": "Name should be less than 256", + "label-max-length": "Label should be less than 256", "description": "Description", "label": "Label", "events": "Events", @@ -1050,6 +1062,7 @@ "set-default": "Make device profile default", "delete": "Delete device profile", "copyId": "Copy device profile Id", + "name-max-length": "Name should be less than 256", "new-device-profile-name": "Device profile name", "new-device-profile-name-required": "Device profile name is required.", "name": "Name", @@ -1401,6 +1414,9 @@ "edge": "Edge", "edge-instances": "Edge instances", "edge-file": "Edge file", + "name-max-length": "Name should be less than 256", + "label-max-length": "Label should be less than 256", + "type-max-length": "Type should be less than 256", "management": "Edge management", "no-edges-matching": "No edges matching '{{entity}}' were found.", "rulechain-templates": "Rule chain templates", @@ -1741,6 +1757,8 @@ "created-time": "Created time", "name": "Name", "name-required": "Name is required.", + "name-max-length": "Name should be less than 256", + "type-max-length": "Entity view type should be less than 256", "description": "Description", "events": "Events", "details": "Details", @@ -2335,12 +2353,14 @@ "selected-package": "{ count, plural, 1 {1 package} other {# packages} } selected", "title": "Title", "title-required": "Title is required.", + "title-max-length": "Title should be less than 256", "types": { "firmware": "Firmware", "software": "Software" }, "version": "Version", "version-required": "Version is required.", + "version-max-length": "Version should be less than 256", "warning-after-save-no-edit": "Once the package is uploaded, you will not be able to modify title, version, device profile and package type." }, "position": { @@ -2379,6 +2399,7 @@ "delete": "Delete relation", "relation-type": "Relation type", "relation-type-required": "Relation type is required.", + "relation-type-max-length": "Relation type should be less than 256", "any-relation-type": "Any type", "add": "Add relation", "edit": "Edit relation", @@ -2423,7 +2444,8 @@ "selected-resources": "{ count, plural, 1 {1 resource} other {# resources} } selected", "system": "System", "title": "Title", - "title-required": "Title is required." + "title-required": "Title is required.", + "title-max-length": "Title should be less than 256" }, "rulechain": { "rulechain": "Rule chain", @@ -2432,6 +2454,7 @@ "delete": "Delete rule chain", "name": "Name", "name-required": "Name is required.", + "name-max-length": "Name should be less than 256", "description": "Description", "add": "Add Rule Chain", "set-root": "Make rule chain root", @@ -2573,6 +2596,7 @@ "add-tenant-text": "Add new tenant", "no-tenants-text": "No tenants found", "tenant-details": "Tenant details", + "title-max-length": "Title should be less than 256", "delete-tenant-title": "Are you sure you want to delete the tenant '{{tenantTitle}}'?", "delete-tenant-text": "Be careful, after the confirmation the tenant and all related data will become unrecoverable.", "delete-tenants-title": "Are you sure you want to delete { count, plural, 1 {1 tenant} other {# tenants} }?", @@ -2602,6 +2626,7 @@ "edit": "Edit tenant profile", "tenant-profile-details": "Tenant profile details", "no-tenant-profiles-text": "No tenant profiles found", + "name-max-length": "Name should be less than 256", "search": "Search tenant profiles", "selected-tenant-profiles": "{ count, plural, 1 {1 tenant profile} other {# tenant profiles} } selected", "no-tenant-profiles-matching": "No tenant profile matching '{{entity}}' were found.", @@ -2925,6 +2950,7 @@ "delete": "Delete widgets bundle", "title": "Title", "title-required": "Title is required.", + "title-max-length": "Title should be less than 256", "description": "Description", "image-preview": "Image preview", "add-widgets-bundle-text": "Add new widgets bundle", From 4bd3288f57430a4bf30891590b1d5a8fee7276c7 Mon Sep 17 00:00:00 2001 From: AndrewVolosytnykhThingsboard Date: Mon, 19 Jul 2021 12:42:42 +0300 Subject: [PATCH 005/303] Tests for fields validation --- .../controller/BaseAssetControllerTest.java | 14 ++++++++++++ .../BaseCustomerControllerTest.java | 22 +++++++++++++++++++ .../BaseDashboardControllerTest.java | 7 ++++++ .../controller/BaseDeviceControllerTest.java | 14 ++++++++++++ .../BaseDeviceProfileControllerTest.java | 7 ++++++ .../controller/BaseEdgeControllerTest.java | 13 +++++++++++ .../BaseEntityViewControllerTest.java | 8 +++++++ .../BaseOtaPackageControllerTest.java | 20 +++++++++++++++++ .../BaseRuleChainControllerTest.java | 9 ++++++++ .../BaseTbResourceControllerTest.java | 12 ++++++++++ .../controller/BaseTenantControllerTest.java | 13 +++++++++++ .../BaseTenantProfileControllerTest.java | 8 +++++++ .../controller/BaseUserControllerTest.java | 22 +++++++++++++++++++ .../BaseWidgetsBundleControllerTest.java | 8 +++++++ .../server/common/data/Tenant.java | 1 - .../server/common/data/asset/Asset.java | 4 ++++ 16 files changed, 181 insertions(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java index 244eb0e05d..e66f4566e8 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java @@ -99,6 +99,20 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { Assert.assertEquals(foundAsset.getName(), savedAsset.getName()); } + @Test + public void testSaveAssetWithViolationOfLengthValidation() throws Exception { + Asset asset = new Asset(); + asset.setName(RandomStringUtils.randomAlphabetic(300)); + asset.setType("default"); + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + asset.setName("Normal name"); + asset.setType(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of type should be equals or less than 255"))); + asset.setType("default"); + asset.setLabel(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of label should be equals or less than 255"))); + } + @Test public void testUpdateAssetFromDifferentTenant() throws Exception { Asset asset = new Asset(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java index 4fbf08e595..c904230283 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java @@ -90,6 +90,28 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest .andExpect(status().isOk()); } + @Test + public void testSaveCustomerWithViolationOfValidation() throws Exception { + Customer customer = new Customer(); + customer.setTitle(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + customer.setTitle("Normal title"); + customer.setCity(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of city should be equals or less than 255"))); + customer.setCity("Normal city"); + customer.setCountry(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of country should be equals or less than 255"))); + customer.setCountry("Ukraine"); + customer.setPhone(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of phone should be equals or less than 255"))); + customer.setPhone("+3892555554512"); + customer.setState(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of state should be equals or less than 255"))); + customer.setState("Normal state"); + customer.setZip(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of zip or postal code should be equals or less than 255"))); + } + @Test public void testUpdateCustomerFromDifferentTenant() throws Exception { Customer customer = new Customer(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java index 60b4128878..b16cdb43ac 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java @@ -93,6 +93,13 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest Assert.assertEquals(foundDashboard.getTitle(), savedDashboard.getTitle()); } + @Test + public void testSaveDashboardInfoWithViolationOfValidation() throws Exception { + Dashboard dashboard = new Dashboard(); + dashboard.setTitle(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/dashboard", dashboard).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + } + @Test public void testUpdateDashboardFromDifferentTenant() throws Exception { Dashboard dashboard = new Dashboard(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java index fa5a6b76eb..866d06a6df 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java @@ -114,6 +114,20 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); } + @Test + public void saveDeviceWithViolationOfValidation() throws Exception { + Device device = new Device(); + device.setName(RandomStringUtils.randomAlphabetic(300)); + device.setType("default"); + doPost("/api/device", device).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + device.setName("Normal Name"); + device.setType(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/device", device).andExpect(statusReason(containsString("length of type should be equals or less than 255"))); + device.setType("Normal type"); + device.setLabel(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/device", device).andExpect(statusReason(containsString("length of label should be equals or less than 255"))); + } + @Test public void testUpdateDeviceFromDifferentTenant() throws Exception { Device device = new Device(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java index ea5a6dbf86..df2cfd2684 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java @@ -22,6 +22,7 @@ import com.google.protobuf.DynamicMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.util.JsonFormat; import com.squareup.wire.schema.internal.parser.ProtoFileElement; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -107,6 +108,12 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfile.getName()); } + @Test + public void saveDeviceProfileWithViolationOfValidation() throws Exception { + doPost("/api/deviceProfile", this.createDeviceProfile(RandomStringUtils.randomAlphabetic(300), null)) + .andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + } + @Test public void testFindDeviceProfileById() throws Exception { DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java index 0d1f6b590d..8e82023455 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java @@ -47,6 +47,7 @@ import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Random; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.nullValue; @@ -111,6 +112,18 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { Assert.assertEquals(foundEdge.getName(), savedEdge.getName()); } + @Test + public void testSaveEdgeWithViolationOfLengthValidation() throws Exception { + Edge edge = constructEdge(RandomStringUtils.randomAlphabetic(300), "default"); + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + edge.setName("normal name"); + edge.setType(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of type should be equals or less than 255"))); + edge.setType("normal type"); + edge.setLabel(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of label should be equals or less than 255"))); + } + @Test public void testFindEdgeById() throws Exception { Edge edge = constructEdge("My edge", "default"); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index e651caa2ff..b1193189aa 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -133,6 +133,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertEquals(foundEntityView.getKeys(), telemetry); } + @Test + public void testSaveEntityViewWithViolationOfValidation() throws Exception { + EntityView entityView = createEntityView(RandomStringUtils.randomAlphabetic(300), 0, 0); + doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + entityView.setName("Normal name"); + entityView.setType(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of type should be equals or less than 255"))); + } @Test public void testUpdateEntityViewFromDifferentTenant() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java index 7026548b25..7e26e2dc84 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -40,6 +41,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; @@ -117,6 +119,24 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); } + @Test + public void saveOtaPackageInfoWithViolationOfLengthValidation() throws Exception { + SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); + firmwareInfo.setTitle(RandomStringUtils.randomAlphabetic(300)); + firmwareInfo.setVersion(VERSION); + firmwareInfo.setUsesUrl(false); + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + firmwareInfo.setTitle(TITLE); + firmwareInfo.setVersion(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of version should be equals or less than 255"))); + firmwareInfo.setVersion(VERSION); + firmwareInfo.setUsesUrl(true); + firmwareInfo.setUrl(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of url should be equals or less than 255"))); + } + @Test public void testSaveFirmwareData() throws Exception { SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java index 67addcd947..77abee25b7 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -33,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; public abstract class BaseRuleChainControllerTest extends AbstractControllerTest { @@ -84,6 +86,13 @@ public abstract class BaseRuleChainControllerTest extends AbstractControllerTest Assert.assertEquals(savedRuleChain.getName(), foundRuleChain.getName()); } + @Test + public void testSaveRuleChainWithViolationOfLengthValidation() throws Exception { + RuleChain ruleChain = new RuleChain(); + ruleChain.setName(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/ruleChain", ruleChain).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + } + @Test public void testFindRuleChainById() throws Exception { RuleChain ruleChain = new RuleChain(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTbResourceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTbResourceControllerTest.java index 8850b70f86..505e0dc636 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTbResourceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTbResourceControllerTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -33,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; public abstract class BaseTbResourceControllerTest extends AbstractControllerTest { @@ -98,6 +100,16 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes Assert.assertEquals(foundResource.getTitle(), savedResource.getTitle()); } + @Test + public void saveResourceInfoWithViolationOfLengthValidation() throws Exception { + TbResource resource = new TbResource(); + resource.setResourceType(ResourceType.JKS); + resource.setTitle(RandomStringUtils.randomAlphabetic(300)); + resource.setFileName(DEFAULT_FILE_NAME); + resource.setData("Test Data"); + doPost("/api/resource", resource).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + } + @Test public void testUpdateTbResourceFromDifferentTenant() throws Exception { TbResource resource = new TbResource(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java index b05dd52bb5..f1ee2899a5 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java @@ -52,6 +52,19 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } + + @Test + public void testSaveTenantWithViolationOfValidation() throws Exception { + loginSysAdmin(); + Tenant tenant = new Tenant(); + tenant.setTitle(RandomStringUtils.randomAlphanumeric(300)); + doPost("/api/tenant", tenant).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + } + + public static void main(String[] args) { + String temp = RandomStringUtils.randomAlphanumeric(300); + System.err.println(temp); + } @Test public void testFindTenantById() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java index c70e7d0178..885bdd4bd1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Test; @@ -74,6 +75,13 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController Assert.assertEquals(foundTenantProfile.getName(), savedTenantProfile.getName()); } + @Test + public void testSaveTenantProfileWithViolationOfLengthValidation() throws Exception { + loginSysAdmin(); + TenantProfile tenantProfile = this.createTenantProfile(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/tenantProfile", tenantProfile).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + } + @Test public void testFindTenantProfileById() throws Exception { loginSysAdmin(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java index 600b9656f2..946b4deeae 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java @@ -105,6 +105,28 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); } + @Test + public void testSaveUserWithViolationOfFiledValidation() throws Exception { + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); + Assert.assertNotNull(savedTenant); + + String email = "tenant2@thingsboard.org"; + User user = new User(); + user.setAuthority(Authority.TENANT_ADMIN); + user.setTenantId(savedTenant.getId()); + user.setEmail(email); + user.setFirstName(RandomStringUtils.randomAlphabetic(300)); + user.setLastName("Downs"); + doPost("/api/user", user).andExpect(statusReason(containsString("Validation error: length of firs name should be equals or less than 255"))); + user.setFirstName("Normal name"); + user.setLastName(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/user", user).andExpect(statusReason(containsString("length of last name should be equals or less than 255"))); + } + @Test public void testUpdateUserFromDifferentTenant() throws Exception { loginSysAdmin(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseWidgetsBundleControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseWidgetsBundleControllerTest.java index 4b16cee03d..4b7fb80ec3 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseWidgetsBundleControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseWidgetsBundleControllerTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -88,6 +89,13 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController Assert.assertEquals(foundWidgetsBundle.getTitle(), savedWidgetsBundle.getTitle()); } + @Test + public void testSaveWidgetBundleWithViolationOfLengthValidation() throws Exception { + WidgetsBundle widgetsBundle = new WidgetsBundle(); + widgetsBundle.setTitle(RandomStringUtils.randomAlphabetic(300)); + doPost("/api/widgetsBundle", widgetsBundle).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + } + @Test public void testUpdateWidgetsBundleFromDifferentTenant() throws Exception { WidgetsBundle widgetsBundle = new WidgetsBundle(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java index 9146212361..f6145516fe 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java @@ -31,7 +31,6 @@ public class Tenant extends ContactBased implements HasTenantId { @Length(fieldName = "title") @NoXss private String title; - @Length(fieldName = "region") @NoXss private String region; private TenantProfileId tenantProfileId; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java index f9d64cb712..5b9ed91ae2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @EqualsAndHashCode(callSuper = true) @@ -33,10 +34,13 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements private TenantId tenantId; private CustomerId customerId; @NoXss + @Length(fieldName = "name") private String name; @NoXss + @Length(fieldName = "type") private String type; @NoXss + @Length(fieldName = "label") private String label; public Asset() { From 75fa28f6fd92d986873010c7ce4b04932bed6e85 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 20 Aug 2021 19:09:04 +0300 Subject: [PATCH 006/303] New Feature add the Select input on multiple input widget --- .../lib/multiple-input-widget.component.html | 18 ++++++++++++++++++ .../lib/multiple-input-widget.component.ts | 12 +++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 5dc5bc4be2..04f568e6bf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -104,6 +104,24 @@
+
+ + {{key.label}} + + + {{ getCustomTranslationText(option.label ? option.label : option.value) }} + + + + {{ getErrorMessageText(key.settings, 'required') }} + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index 8d9d904368..b4485df5f8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -41,7 +41,7 @@ type FieldAlignment = 'row' | 'column'; type MultipleInputWidgetDataKeyType = 'server' | 'shared' | 'timeseries'; type MultipleInputWidgetDataKeyValueType = 'string' | 'double' | 'integer' | 'booleanCheckbox' | 'booleanSwitch' | - 'dateTime' | 'date' | 'time'; + 'dateTime' | 'date' | 'time' | 'select'; type MultipleInputWidgetDataKeyEditableType = 'editable' | 'disabled' | 'readonly'; interface MultipleInputWidgetSettings { @@ -58,9 +58,15 @@ interface MultipleInputWidgetSettings { attributesShared?: boolean; } +interface MultipleInputWidgetSelectOption { + value: string; + label: string; +} + interface MultipleInputWidgetDataKeySettings { dataKeyType: MultipleInputWidgetDataKeyType; dataKeyValueType: MultipleInputWidgetDataKeyValueType; + selectOptions: MultipleInputWidgetSelectOption[]; required: boolean; isEditable: MultipleInputWidgetDataKeyEditableType; disabledOnDataKey: string; @@ -445,6 +451,10 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni return messageText; } + public getCustomTranslationText(value): string { + return this.utils.customTranslation(value, value); + } + public visibleKeys(source: MultipleInputWidgetSource): MultipleInputWidgetDataKey[] { return source.keys.filter(key => !key.settings.dataKeyHidden); } From 779a82c99230a865bf32949294e3d74e72854d13 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 26 Aug 2021 16:47:55 +0300 Subject: [PATCH 007/303] add method toLowerCase to option value --- .../components/widget/lib/multiple-input-widget.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 04f568e6bf..bf225cda84 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -112,7 +112,7 @@ (focus)="key.isFocused = true;" (blur)="key.isFocused = false; inputChanged(source, key)"> {{ getCustomTranslationText(option.label ? option.label : option.value) }} From 8f6e27a7361ae2912cc0880f66d82a05019dc651 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 26 Aug 2021 17:19:39 +0300 Subject: [PATCH 008/303] add setingsSchema --- .../main/data/json/system/widget_bundles/input_widgets.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/input_widgets.json b/application/src/main/data/json/system/widget_bundles/input_widgets.json index c215ed2263..8307b98dfa 100644 --- a/application/src/main/data/json/system/widget_bundles/input_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/input_widgets.json @@ -38,8 +38,8 @@ "templateCss": ".tb-toast {\n min-width: 0;\n font-size: 14px !important;\n}", "controllerScript": "self.onInit = function() {\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n self.ctx.$scope.multipleInputWidget.onDataUpdated();\r\n}\r\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"MultipleInput\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showActionButtons\":{\n \"title\":\"Show action buttons\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"updateAllValues\": {\n \"title\":\"Update all values, not only modified\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"saveButtonLabel\": {\n \"title\": \"'SAVE' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"resetButtonLabel\": {\n \"title\": \"'UNDO' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"showGroupTitle\": {\n \"title\":\"Show title for group of fields, related to different entities\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"groupTitle\": {\n \"title\": \"Group title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"fieldsAlignment\": {\n \"title\": \"Fields alignment\",\n \"type\": \"string\",\n \"default\": \"row\"\n },\n \"fieldsInRow\": {\n \"title\": \"Number of fields in the row\",\n \"type\": \"number\",\n \"default\": \"2\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showActionButtons\",\n {\n \"key\": \"updateAllValues\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"saveButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"resetButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n \"showResultMessage\",\n \"showGroupTitle\",\n \"groupTitle\",\n {\n \"key\": \"fieldsAlignment\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"row\",\n \"label\": \"Row (default)\"\n },\n {\n \"value\": \"column\",\n \"label\": \"Column\"\n }\n ]\n },\n {\n \"key\": \"fieldsInRow\",\n \"condition\": \"model.fieldsAlignment === 'row'\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n }\n ]\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update Multiple Attributes\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"selectOptions\": {\n \"title\": \"Select options\",\n \"type\": \"array\",\n \"items\": {\n \"title\": \"Option\",\n \"description\": \"label\",\n \"type\": \"object\",\n \"properties\": {\n \"value\": {\n \"title\": \"Value (null for create empty option)\",\n \"type\": \"string\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"value\"]\n }\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n },\n {\n \"value\": \"select\",\n \"label\": \"Select\"\n }\n ]\n },\n {\n \"key\": \"selectOptions\",\n \"condition\": \"model.dataKeyValueType === 'select'\"\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"groupTitle\":\"${entityName}\",\"showActionButtons\":true,\"fieldsAlignment\":\"row\",\"fieldsInRow\":2,\"showResultMessage\":true},\"title\":\"Update Multiple Attributes\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" } }, { From 659a9af0bc4af18ab7d7f864a7d262bdf95eadff Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 26 Aug 2021 18:07:03 +0300 Subject: [PATCH 009/303] fix defaultConfig --- .../src/main/data/json/system/widget_bundles/input_widgets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_bundles/input_widgets.json b/application/src/main/data/json/system/widget_bundles/input_widgets.json index 8307b98dfa..dff14980bc 100644 --- a/application/src/main/data/json/system/widget_bundles/input_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/input_widgets.json @@ -39,7 +39,7 @@ "controllerScript": "self.onInit = function() {\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n self.ctx.$scope.multipleInputWidget.onDataUpdated();\r\n}\r\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"MultipleInput\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showActionButtons\":{\n \"title\":\"Show action buttons\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"updateAllValues\": {\n \"title\":\"Update all values, not only modified\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"saveButtonLabel\": {\n \"title\": \"'SAVE' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"resetButtonLabel\": {\n \"title\": \"'UNDO' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"showGroupTitle\": {\n \"title\":\"Show title for group of fields, related to different entities\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"groupTitle\": {\n \"title\": \"Group title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"fieldsAlignment\": {\n \"title\": \"Fields alignment\",\n \"type\": \"string\",\n \"default\": \"row\"\n },\n \"fieldsInRow\": {\n \"title\": \"Number of fields in the row\",\n \"type\": \"number\",\n \"default\": \"2\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showActionButtons\",\n {\n \"key\": \"updateAllValues\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"saveButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"resetButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n \"showResultMessage\",\n \"showGroupTitle\",\n \"groupTitle\",\n {\n \"key\": \"fieldsAlignment\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"row\",\n \"label\": \"Row (default)\"\n },\n {\n \"value\": \"column\",\n \"label\": \"Column\"\n }\n ]\n },\n {\n \"key\": \"fieldsInRow\",\n \"condition\": \"model.fieldsAlignment === 'row'\"\n }\n ]\n}", "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"selectOptions\": {\n \"title\": \"Select options\",\n \"type\": \"array\",\n \"items\": {\n \"title\": \"Option\",\n \"description\": \"label\",\n \"type\": \"object\",\n \"properties\": {\n \"value\": {\n \"title\": \"Value (null for create empty option)\",\n \"type\": \"string\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"value\"]\n }\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n },\n {\n \"value\": \"select\",\n \"label\": \"Select\"\n }\n ]\n },\n {\n \"key\": \"selectOptions\",\n \"condition\": \"model.dataKeyValueType === 'select'\"\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"groupTitle\":\"${entityName}\",\"showActionButtons\":true,\"fieldsAlignment\":\"row\",\"fieldsInRow\":2,\"showResultMessage\":true},\"title\":\"Update Multiple Attributes\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update Multiple Attributes\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" } }, { From 2608c46c94cb2e93f21d59d49da99b67dbe334a6 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 27 Aug 2021 11:57:04 +0300 Subject: [PATCH 010/303] fix setingsSchema and add return empty string for custom translate --- .../main/data/json/system/widget_bundles/input_widgets.json | 2 +- .../components/widget/lib/multiple-input-widget.component.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_bundles/input_widgets.json b/application/src/main/data/json/system/widget_bundles/input_widgets.json index dff14980bc..8651f6e75e 100644 --- a/application/src/main/data/json/system/widget_bundles/input_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/input_widgets.json @@ -38,7 +38,7 @@ "templateCss": ".tb-toast {\n min-width: 0;\n font-size: 14px !important;\n}", "controllerScript": "self.onInit = function() {\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n self.ctx.$scope.multipleInputWidget.onDataUpdated();\r\n}\r\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"MultipleInput\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showActionButtons\":{\n \"title\":\"Show action buttons\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"updateAllValues\": {\n \"title\":\"Update all values, not only modified\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"saveButtonLabel\": {\n \"title\": \"'SAVE' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"resetButtonLabel\": {\n \"title\": \"'UNDO' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"showGroupTitle\": {\n \"title\":\"Show title for group of fields, related to different entities\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"groupTitle\": {\n \"title\": \"Group title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"fieldsAlignment\": {\n \"title\": \"Fields alignment\",\n \"type\": \"string\",\n \"default\": \"row\"\n },\n \"fieldsInRow\": {\n \"title\": \"Number of fields in the row\",\n \"type\": \"number\",\n \"default\": \"2\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showActionButtons\",\n {\n \"key\": \"updateAllValues\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"saveButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"resetButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n \"showResultMessage\",\n \"showGroupTitle\",\n \"groupTitle\",\n {\n \"key\": \"fieldsAlignment\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"row\",\n \"label\": \"Row (default)\"\n },\n {\n \"value\": \"column\",\n \"label\": \"Column\"\n }\n ]\n },\n {\n \"key\": \"fieldsInRow\",\n \"condition\": \"model.fieldsAlignment === 'row'\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"selectOptions\": {\n \"title\": \"Select options\",\n \"type\": \"array\",\n \"items\": {\n \"title\": \"Option\",\n \"description\": \"label\",\n \"type\": \"object\",\n \"properties\": {\n \"value\": {\n \"title\": \"Value (null for create empty option)\",\n \"type\": \"string\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"value\"]\n }\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n },\n {\n \"value\": \"select\",\n \"label\": \"Select\"\n }\n ]\n },\n {\n \"key\": \"selectOptions\",\n \"condition\": \"model.dataKeyValueType === 'select'\"\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"selectOptions\": {\n \"title\": \"Select options\",\n \"type\": \"array\",\n \"items\": {\n \"title\": \"Option\",\n \"type\": \"object\",\n \"properties\": {\n \"value\": {\n \"title\": \"Value (write 'null' for create empty option)\",\n \"type\": \"string\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"value\"]\n }\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n },\n {\n \"value\": \"select\",\n \"label\": \"Select\"\n }\n ]\n },\n {\n \"key\": \"selectOptions\",\n \"condition\": \"model.dataKeyValueType === 'select'\"\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update Multiple Attributes\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" } }, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index b4485df5f8..04f835b718 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -452,6 +452,10 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } public getCustomTranslationText(value): string { + if (value.toLowerCase() === 'null') { + return ''; + } + return this.utils.customTranslation(value, value); } From 1e3dfc33b2d7811f0d7044a02aea391b8170613a Mon Sep 17 00:00:00 2001 From: Swoq Date: Mon, 30 Aug 2021 17:38:13 +0300 Subject: [PATCH 011/303] Delegation of exception handling logic to the ThingsboardErrorResponseHandler Any thrown Exception casts to the ThingsBoardException. --- .../server/controller/BaseController.java | 23 +++------------- .../controller/TelemetryController.java | 8 ++---- .../ThingsboardErrorResponseHandler.java | 27 ++++++++++++++++--- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index c37587f546..d120f1b01a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -281,6 +281,9 @@ public abstract class BaseController { @Autowired protected RuleEngineEntityActionService ruleEngineEntityActionService; + @Autowired + protected ThingsboardErrorResponseHandler thingsboardErrorResponseHandler; + @Value("${server.log_controller_error_stack_trace}") @Getter private boolean logControllerErrorStackTrace; @@ -299,25 +302,7 @@ public abstract class BaseController { } private ThingsboardException handleException(Exception exception, boolean logException) { - if (logException && logControllerErrorStackTrace) { - log.error("Error [{}]", exception.getMessage(), exception); - } - - String cause = ""; - if (exception.getCause() != null) { - cause = exception.getCause().getClass().getCanonicalName(); - } - - if (exception instanceof ThingsboardException) { - return (ThingsboardException) exception; - } else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException - || exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { - return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); - } else if (exception instanceof MessagingException) { - return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); - } else { - return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.GENERAL); - } + return thingsboardErrorResponseHandler.castToThingsboardException(exception, logException); } T checkNotNull(T reference) throws ThingsboardException { 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 7ec626bcdf..16e25d5c2d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -269,12 +269,8 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityAttributesV1(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - try { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); - } catch (Exception e) { - throw handleException(e); - } + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java index 906e87d608..e5cb553a3d 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java @@ -34,10 +34,13 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.msg.tools.TbRateLimitsException; +import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; import org.thingsboard.server.service.security.exception.JwtExpiredTokenException; import org.thingsboard.server.service.security.exception.UserPasswordExpiredException; +import javax.mail.MessagingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -85,9 +88,7 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand } else if (exception instanceof AuthenticationException) { handleAuthenticationException((AuthenticationException) exception, response); } else { - response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); - mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(exception.getMessage(), - ThingsboardErrorCode.GENERAL, HttpStatus.INTERNAL_SERVER_ERROR)); + handle(castToThingsboardException(exception, true), response); } } catch (IOException e) { log.error("Can't handle exception", e); @@ -95,6 +96,26 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand } } + public ThingsboardException castToThingsboardException(Exception exception, boolean logException) { + if (logException) { + log.error("Error [{}]", exception.getMessage(), exception); + } + + String cause = ""; + if (exception.getCause() != null) { + cause = exception.getCause().getClass().getCanonicalName(); + } + + if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException + || exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { + return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } else if (exception instanceof MessagingException) { + return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); + } else { + return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.GENERAL); + } + } + private void handleThingsboardException(ThingsboardException thingsboardException, HttpServletResponse response) throws IOException { From da5758b798eb891c9f748d32a38f420ec67148bc Mon Sep 17 00:00:00 2001 From: Swoq Date: Mon, 30 Aug 2021 18:05:09 +0300 Subject: [PATCH 012/303] ThingsboardErrorResponseHandler now work with: - IllegalArgumentException, IncorrectParameterException, DataValidationException, MessagingException. They aren't considered to be an internal server error now. --- .../server/controller/BaseController.java | 23 +++- .../controller/TelemetryController.java | 130 +++++------------- .../ThingsboardErrorResponseHandler.java | 36 ++--- .../controller/BaseAssetControllerTest.java | 6 +- .../BaseCustomerControllerTest.java | 12 +- .../BaseDashboardControllerTest.java | 2 +- .../controller/BaseDeviceControllerTest.java | 6 +- .../BaseDeviceProfileControllerTest.java | 2 +- .../controller/BaseEdgeControllerTest.java | 6 +- .../BaseEntityViewControllerTest.java | 4 +- .../BaseOtaPackageControllerTest.java | 6 +- .../BaseRuleChainControllerTest.java | 2 +- .../BaseTbResourceControllerTest.java | 2 +- .../controller/BaseTenantControllerTest.java | 2 +- .../BaseTenantProfileControllerTest.java | 2 +- .../controller/BaseUserControllerTest.java | 4 +- .../BaseWidgetsBundleControllerTest.java | 2 +- .../server/common/data/OtaPackageInfo.java | 7 + .../server/common/data/validation/Length.java | 2 +- 19 files changed, 107 insertions(+), 149 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index d120f1b01a..c37587f546 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -281,9 +281,6 @@ public abstract class BaseController { @Autowired protected RuleEngineEntityActionService ruleEngineEntityActionService; - @Autowired - protected ThingsboardErrorResponseHandler thingsboardErrorResponseHandler; - @Value("${server.log_controller_error_stack_trace}") @Getter private boolean logControllerErrorStackTrace; @@ -302,7 +299,25 @@ public abstract class BaseController { } private ThingsboardException handleException(Exception exception, boolean logException) { - return thingsboardErrorResponseHandler.castToThingsboardException(exception, logException); + if (logException && logControllerErrorStackTrace) { + log.error("Error [{}]", exception.getMessage(), exception); + } + + String cause = ""; + if (exception.getCause() != null) { + cause = exception.getCause().getClass().getCanonicalName(); + } + + if (exception instanceof ThingsboardException) { + return (ThingsboardException) exception; + } else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException + || exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { + return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } else if (exception instanceof MessagingException) { + return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); + } else { + return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.GENERAL); + } } T checkNotNull(T reference) throws ThingsboardException { 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 16e25d5c2d..592a332a00 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -138,11 +138,7 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult getAttributeKeys( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { - try { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); - } catch (Exception e) { - throw handleException(e); - } + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -151,12 +147,8 @@ public class TelemetryController extends BaseController { public DeferredResult getAttributeKeysByScope( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr , @PathVariable("scope") String scope) throws ThingsboardException { - try { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); - } catch (Exception e) { - throw handleException(e); - } + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -165,13 +157,9 @@ public class TelemetryController extends BaseController { public DeferredResult getAttributes( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { - try { - SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); - } catch (Exception e) { - throw handleException(e); - } + SecurityUser user = getCurrentUser(); + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -181,13 +169,9 @@ public class TelemetryController extends BaseController { @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { - try { - SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); - } catch (Exception e) { - throw handleException(e); - } + SecurityUser user = getCurrentUser(); + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -195,12 +179,8 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult getTimeseriesKeys( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { - try { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); - } catch (Exception e) { - throw handleException(e); - } + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -210,14 +190,10 @@ public class TelemetryController extends BaseController { @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @RequestParam(name = "keys", required = false) String keysStr, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { - try { - SecurityUser user = getCurrentUser(); + SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); - } catch (Exception e) { - throw handleException(e); - } + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); } @@ -235,19 +211,15 @@ public class TelemetryController extends BaseController { @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { - try { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> { - // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted - Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); - List queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) - .collect(Collectors.toList()); - - Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); - }); - } catch (Exception e) { - throw handleException(e); - } + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> { + // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted + Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); + List queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) + .collect(Collectors.toList()); + + Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); + }); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -255,12 +227,8 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult saveDeviceAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - try { - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); - } catch (Exception e) { - throw handleException(e); - } + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -279,12 +247,8 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityAttributesV2(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - try { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); - } catch (Exception e) { - throw handleException(e); - } + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -293,12 +257,8 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetry(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody String requestBody) throws ThingsboardException { - try { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveTelemetry(getTenantId(), entityId, requestBody, 0L); - } catch (Exception e) { - throw handleException(e); - } + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveTelemetry(getTenantId(), entityId, requestBody, 0L); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -307,12 +267,8 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetryWithTTL(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @PathVariable("ttl") Long ttl, @RequestBody String requestBody) throws ThingsboardException { - try { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveTelemetry(getTenantId(), entityId, requestBody, ttl); - } catch (Exception e) { - throw handleException(e); - } + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveTelemetry(getTenantId(), entityId, requestBody, ttl); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -324,12 +280,8 @@ public class TelemetryController extends BaseController { @RequestParam(name = "startTs", required = false) Long startTs, @RequestParam(name = "endTs", required = false) Long endTs, @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { - try { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); - } catch (Exception e) { - throw handleException(e); - } + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); } private DeferredResult deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys, @@ -383,12 +335,8 @@ public class TelemetryController extends BaseController { public DeferredResult deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys") String keysStr) throws ThingsboardException { - try { - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); - return deleteAttributes(entityId, scope, keysStr); - } catch (Exception e) { - throw handleException(e); - } + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); + return deleteAttributes(entityId, scope, keysStr); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -397,12 +345,8 @@ public class TelemetryController extends BaseController { public DeferredResult deleteEntityAttributes(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys") String keysStr) throws ThingsboardException { - try { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return deleteAttributes(entityId, scope, keysStr); - } catch (Exception e) { - throw handleException(e); - } + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return deleteAttributes(entityId, scope, keysStr); } private DeferredResult deleteAttributes(EntityId entityIdSrc, String scope, String keysStr) throws ThingsboardException { diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java index e5cb553a3d..225cfc9097 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java @@ -74,6 +74,17 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand try { response.setContentType(MediaType.APPLICATION_JSON_VALUE); + String cause = ""; + if (exception.getCause() != null) { + cause = exception.getCause().getClass().getCanonicalName(); + } + if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException + || exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { + exception = new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } else if (exception instanceof MessagingException) { + exception = new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); + } + if (exception instanceof ThingsboardException) { ThingsboardException thingsboardException = (ThingsboardException) exception; if (thingsboardException.getErrorCode() == ThingsboardErrorCode.SUBSCRIPTION_VIOLATION) { @@ -88,7 +99,9 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand } else if (exception instanceof AuthenticationException) { handleAuthenticationException((AuthenticationException) exception, response); } else { - handle(castToThingsboardException(exception, true), response); + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(exception.getMessage(), + ThingsboardErrorCode.GENERAL, HttpStatus.INTERNAL_SERVER_ERROR)); } } catch (IOException e) { log.error("Can't handle exception", e); @@ -96,27 +109,6 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand } } - public ThingsboardException castToThingsboardException(Exception exception, boolean logException) { - if (logException) { - log.error("Error [{}]", exception.getMessage(), exception); - } - - String cause = ""; - if (exception.getCause() != null) { - cause = exception.getCause().getClass().getCanonicalName(); - } - - if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException - || exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { - return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); - } else if (exception instanceof MessagingException) { - return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); - } else { - return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.GENERAL); - } - } - - private void handleThingsboardException(ThingsboardException thingsboardException, HttpServletResponse response) throws IOException { ThingsboardErrorCode errorCode = thingsboardException.getErrorCode(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java index e66f4566e8..c72b732ff6 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java @@ -104,13 +104,13 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { Asset asset = new Asset(); asset.setName(RandomStringUtils.randomAlphabetic(300)); asset.setType("default"); - doPost("/api/asset", asset).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); asset.setName("Normal name"); asset.setType(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/asset", asset).andExpect(statusReason(containsString("length of type should be equals or less than 255"))); + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); asset.setType("default"); asset.setLabel(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/asset", asset).andExpect(statusReason(containsString("length of label should be equals or less than 255"))); + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of label must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java index c904230283..318e1413a0 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java @@ -94,22 +94,22 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest public void testSaveCustomerWithViolationOfValidation() throws Exception { Customer customer = new Customer(); customer.setTitle(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/customer", customer).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); customer.setTitle("Normal title"); customer.setCity(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/customer", customer).andExpect(statusReason(containsString("length of city should be equals or less than 255"))); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of city must be equal or less than 255"))); customer.setCity("Normal city"); customer.setCountry(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/customer", customer).andExpect(statusReason(containsString("length of country should be equals or less than 255"))); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of country must be equal or less than 255"))); customer.setCountry("Ukraine"); customer.setPhone(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/customer", customer).andExpect(statusReason(containsString("length of phone should be equals or less than 255"))); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of phone must be equal or less than 255"))); customer.setPhone("+3892555554512"); customer.setState(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/customer", customer).andExpect(statusReason(containsString("length of state should be equals or less than 255"))); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of state must be equal or less than 255"))); customer.setState("Normal state"); customer.setZip(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/customer", customer).andExpect(statusReason(containsString("length of zip or postal code should be equals or less than 255"))); + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of zip or postal code must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java index b16cdb43ac..18fa8bdd5d 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java @@ -97,7 +97,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest public void testSaveDashboardInfoWithViolationOfValidation() throws Exception { Dashboard dashboard = new Dashboard(); dashboard.setTitle(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/dashboard", dashboard).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + doPost("/api/dashboard", dashboard).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java index 866d06a6df..c31f5c7daf 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java @@ -119,13 +119,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { Device device = new Device(); device.setName(RandomStringUtils.randomAlphabetic(300)); device.setType("default"); - doPost("/api/device", device).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + doPost("/api/device", device).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); device.setName("Normal Name"); device.setType(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/device", device).andExpect(statusReason(containsString("length of type should be equals or less than 255"))); + doPost("/api/device", device).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); device.setType("Normal type"); device.setLabel(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/device", device).andExpect(statusReason(containsString("length of label should be equals or less than 255"))); + doPost("/api/device", device).andExpect(statusReason(containsString("length of label must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java index 8696c7e499..d33a93cd64 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java @@ -113,7 +113,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @Test public void saveDeviceProfileWithViolationOfValidation() throws Exception { doPost("/api/deviceProfile", this.createDeviceProfile(RandomStringUtils.randomAlphabetic(300), null)) - .andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + .andExpect(statusReason(containsString("length of name must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java index 40529d40e8..9259f3253d 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java @@ -116,13 +116,13 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { @Test public void testSaveEdgeWithViolationOfLengthValidation() throws Exception { Edge edge = constructEdge(RandomStringUtils.randomAlphabetic(300), "default"); - doPost("/api/edge", edge).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); edge.setName("normal name"); edge.setType(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/edge", edge).andExpect(statusReason(containsString("length of type should be equals or less than 255"))); + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); edge.setType("normal type"); edge.setLabel(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/edge", edge).andExpect(statusReason(containsString("length of label should be equals or less than 255"))); + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of label must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index b1193189aa..304964dfa8 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -136,10 +136,10 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes @Test public void testSaveEntityViewWithViolationOfValidation() throws Exception { EntityView entityView = createEntityView(RandomStringUtils.randomAlphabetic(300), 0, 0); - doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); entityView.setName("Normal name"); entityView.setType(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of type should be equals or less than 255"))); + doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java index 7e26e2dc84..065fc4bab3 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java @@ -127,14 +127,14 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes firmwareInfo.setTitle(RandomStringUtils.randomAlphabetic(300)); firmwareInfo.setVersion(VERSION); firmwareInfo.setUsesUrl(false); - doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of version should be equals or less than 255"))); + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of version must be equal or less than 255"))); firmwareInfo.setVersion(VERSION); firmwareInfo.setUsesUrl(true); firmwareInfo.setUrl(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of url should be equals or less than 255"))); + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of url must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java index 77abee25b7..6363ca3a67 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java @@ -90,7 +90,7 @@ public abstract class BaseRuleChainControllerTest extends AbstractControllerTest public void testSaveRuleChainWithViolationOfLengthValidation() throws Exception { RuleChain ruleChain = new RuleChain(); ruleChain.setName(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/ruleChain", ruleChain).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + doPost("/api/ruleChain", ruleChain).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTbResourceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTbResourceControllerTest.java index 505e0dc636..11a8ff7718 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTbResourceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTbResourceControllerTest.java @@ -107,7 +107,7 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes resource.setTitle(RandomStringUtils.randomAlphabetic(300)); resource.setFileName(DEFAULT_FILE_NAME); resource.setData("Test Data"); - doPost("/api/resource", resource).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + doPost("/api/resource", resource).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java index f1ee2899a5..9db4c1aab0 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java @@ -58,7 +58,7 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle(RandomStringUtils.randomAlphanumeric(300)); - doPost("/api/tenant", tenant).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + doPost("/api/tenant", tenant).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); } public static void main(String[] args) { diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java index 885bdd4bd1..26a84aa6a8 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java @@ -79,7 +79,7 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController public void testSaveTenantProfileWithViolationOfLengthValidation() throws Exception { loginSysAdmin(); TenantProfile tenantProfile = this.createTenantProfile(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/tenantProfile", tenantProfile).andExpect(statusReason(containsString("length of name should be equals or less than 255"))); + doPost("/api/tenantProfile", tenantProfile).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java index 946b4deeae..7e378ea2dd 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java @@ -121,10 +121,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { user.setEmail(email); user.setFirstName(RandomStringUtils.randomAlphabetic(300)); user.setLastName("Downs"); - doPost("/api/user", user).andExpect(statusReason(containsString("Validation error: length of firs name should be equals or less than 255"))); + doPost("/api/user", user).andExpect(statusReason(containsString("Validation error: length of firs name must be equal or less than 255"))); user.setFirstName("Normal name"); user.setLastName(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/user", user).andExpect(statusReason(containsString("length of last name should be equals or less than 255"))); + doPost("/api/user", user).andExpect(statusReason(containsString("length of last name must be equal or less than 255"))); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseWidgetsBundleControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseWidgetsBundleControllerTest.java index 4b7fb80ec3..3167466d93 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseWidgetsBundleControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseWidgetsBundleControllerTest.java @@ -93,7 +93,7 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController public void testSaveWidgetBundleWithViolationOfLengthValidation() throws Exception { WidgetsBundle widgetsBundle = new WidgetsBundle(); widgetsBundle.setTitle(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/widgetsBundle", widgetsBundle).andExpect(statusReason(containsString("length of title should be equals or less than 255"))); + doPost("/api/widgetsBundle", widgetsBundle).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); } @Test diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java index a442022e8d..75c8c4b289 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.validation.Length; +import org.thingsboard.server.common.data.validation.NoXss; @Slf4j @Data @@ -37,14 +38,20 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo Date: Wed, 1 Sep 2021 15:44:49 +0300 Subject: [PATCH 013/303] fix selectedOption value --- .../lib/multiple-input-widget.component.html | 2 +- .../widget/lib/multiple-input-widget.component.ts | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index bf225cda84..8865b06b8e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -112,7 +112,7 @@ (focus)="key.isFocused = true;" (blur)="key.isFocused = false; inputChanged(source, key)"> {{ getCustomTranslationText(option.label ? option.label : option.value) }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index 04f835b718..f7c681135e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -59,7 +59,7 @@ interface MultipleInputWidgetSettings { } interface MultipleInputWidgetSelectOption { - value: string; + value: string | null; label: string; } @@ -253,6 +253,14 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } // For backward compatibility + if (dataKey.settings.dataKeyValueType === 'select') { + dataKey.settings.selectOptions.forEach((option) => { + if (option.value.toLowerCase() === 'null') { + option.value = null; + } + }); + } + source.keys.push(dataKey); }); } else { @@ -452,10 +460,6 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } public getCustomTranslationText(value): string { - if (value.toLowerCase() === 'null') { - return ''; - } - return this.utils.customTranslation(value, value); } From e41768f2c8a200844bfc1300c5f11bc57ebf501b Mon Sep 17 00:00:00 2001 From: Swoq Date: Wed, 1 Sep 2021 17:52:39 +0300 Subject: [PATCH 014/303] Tests fix --- .../server/controller/BaseTenantControllerTest.java | 5 ----- .../server/dao/service/BaseOtaPackageServiceTest.java | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java index 9db4c1aab0..51a7d81df8 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java @@ -60,11 +60,6 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { tenant.setTitle(RandomStringUtils.randomAlphanumeric(300)); doPost("/api/tenant", tenant).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); } - - public static void main(String[] args) { - String temp = RandomStringUtils.randomAlphanumeric(300); - System.err.println(temp); - } @Test public void testFindTenantById() throws Exception { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index 1bf71370ea..c7c41f69be 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -673,7 +673,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setTenantId(tenantId); thrown.expect(DataValidationException.class); - thrown.expectMessage("The length of title should be equal or shorter than 255"); + thrown.expectMessage("The length of title must be equal or shorter than 255"); otaPackageService.saveOtaPackageInfo(firmwareInfo, true); } @@ -688,7 +688,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(RandomStringUtils.random(257)); - thrown.expectMessage("The length of version should be equal or shorter than 255"); + thrown.expectMessage("The length of version must be equal or shorter than 255"); otaPackageService.saveOtaPackageInfo(firmwareInfo, true); } From 6f1a5ea54a353905629d2a5375f0308353e0e87c Mon Sep 17 00:00:00 2001 From: Swoq Date: Wed, 1 Sep 2021 18:12:17 +0300 Subject: [PATCH 015/303] Tests fix --- .../server/dao/service/BaseOtaPackageServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index c7c41f69be..10bc49ac28 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -673,7 +673,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setTenantId(tenantId); thrown.expect(DataValidationException.class); - thrown.expectMessage("The length of title must be equal or shorter than 255"); + thrown.expectMessage("length of title must be equal or less than 255"); otaPackageService.saveOtaPackageInfo(firmwareInfo, true); } @@ -688,7 +688,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(RandomStringUtils.random(257)); - thrown.expectMessage("The length of version must be equal or shorter than 255"); + thrown.expectMessage("length of version must be equal or less than 255"); otaPackageService.saveOtaPackageInfo(firmwareInfo, true); } From 57cec85bb1e4fd8a965a545a1dc2de2bc48d5c4c Mon Sep 17 00:00:00 2001 From: Swoq Date: Wed, 1 Sep 2021 18:31:09 +0300 Subject: [PATCH 016/303] Tests fix --- .../server/dao/service/BaseOtaPackageServiceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index 10bc49ac28..af8f182d8b 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.exception.DataValidationException; +import javax.validation.ValidationException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -672,7 +673,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setUrl(URL); firmwareInfo.setTenantId(tenantId); - thrown.expect(DataValidationException.class); + thrown.expect(ValidationException.class); thrown.expectMessage("length of title must be equal or less than 255"); otaPackageService.saveOtaPackageInfo(firmwareInfo, true); From 827da31d92bf52a3a25e06ecaf83a2497395b0b6 Mon Sep 17 00:00:00 2001 From: Swoq Date: Thu, 2 Sep 2021 10:23:02 +0300 Subject: [PATCH 017/303] Validation fixes --- .../src/main/java/org/thingsboard/server/common/data/User.java | 2 +- .../thingsboard/server/common/data/widget/WidgetsBundle.java | 1 + .../thingsboard/server/dao/service/StringLengthValidator.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/User.java b/common/data/src/main/java/org/thingsboard/server/common/data/User.java index a7135ea56f..ab334dfeab 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/User.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/User.java @@ -36,7 +36,7 @@ public class User extends SearchTextBasedWithAdditionalInfo implements H private String email; private Authority authority; @NoXss - @Length(fieldName = "firs name") + @Length(fieldName = "first name") private String firstName; @NoXss @Length(fieldName = "last name") diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java index fcf3eb9fac..468b409c3e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java @@ -28,6 +28,7 @@ public class WidgetsBundle extends SearchTextBased implements H private TenantId tenantId; @NoXss + @Length(fieldName = "alias") private String alias; @NoXss @Length(fieldName = "title") diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/StringLengthValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/StringLengthValidator.java index 1efa0192e0..b7d9d3991e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/StringLengthValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/StringLengthValidator.java @@ -31,7 +31,7 @@ public class StringLengthValidator implements ConstraintValidator Date: Thu, 2 Sep 2021 16:26:58 +0300 Subject: [PATCH 018/303] Fix logging exceptions of controllers --- .../controller/TelemetryController.java | 138 +++++++++++++----- .../ThingsboardErrorResponseHandler.java | 14 -- .../common/data/widget/WidgetsBundle.java | 1 + 3 files changed, 100 insertions(+), 53 deletions(-) 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 592a332a00..7ec626bcdf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -138,7 +138,11 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult getAttributeKeys( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); + try { + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -147,8 +151,12 @@ public class TelemetryController extends BaseController { public DeferredResult getAttributeKeysByScope( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr , @PathVariable("scope") String scope) throws ThingsboardException { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); + try { + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -157,9 +165,13 @@ public class TelemetryController extends BaseController { public DeferredResult getAttributes( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { - SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); + try { + SecurityUser user = getCurrentUser(); + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -169,9 +181,13 @@ public class TelemetryController extends BaseController { @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { - SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); + try { + SecurityUser user = getCurrentUser(); + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -179,8 +195,12 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult getTimeseriesKeys( @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); + try { + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -190,10 +210,14 @@ public class TelemetryController extends BaseController { @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @RequestParam(name = "keys", required = false) String keysStr, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { - SecurityUser user = getCurrentUser(); + try { + SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); + } catch (Exception e) { + throw handleException(e); + } } @@ -211,15 +235,19 @@ public class TelemetryController extends BaseController { @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, - (result, tenantId, entityId) -> { - // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted - Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); - List queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) - .collect(Collectors.toList()); - - Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); - }); + try { + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, + (result, tenantId, entityId) -> { + // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted + Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); + List queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) + .collect(Collectors.toList()); + + Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); + }); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -227,8 +255,12 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult saveDeviceAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); + try { + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -237,8 +269,12 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityAttributesV1(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -247,8 +283,12 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityAttributesV2(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody JsonNode request) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveAttributes(getTenantId(), entityId, scope, request); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveAttributes(getTenantId(), entityId, scope, request); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -257,8 +297,12 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetry(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestBody String requestBody) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveTelemetry(getTenantId(), entityId, requestBody, 0L); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveTelemetry(getTenantId(), entityId, requestBody, 0L); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -267,8 +311,12 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetryWithTTL(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @PathVariable("ttl") Long ttl, @RequestBody String requestBody) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return saveTelemetry(getTenantId(), entityId, requestBody, ttl); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return saveTelemetry(getTenantId(), entityId, requestBody, ttl); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -280,8 +328,12 @@ public class TelemetryController extends BaseController { @RequestParam(name = "startTs", required = false) Long startTs, @RequestParam(name = "endTs", required = false) Long endTs, @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); + } catch (Exception e) { + throw handleException(e); + } } private DeferredResult deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys, @@ -335,8 +387,12 @@ public class TelemetryController extends BaseController { public DeferredResult deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys") String keysStr) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); - return deleteAttributes(entityId, scope, keysStr); + try { + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); + return deleteAttributes(entityId, scope, keysStr); + } catch (Exception e) { + throw handleException(e); + } } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @@ -345,8 +401,12 @@ public class TelemetryController extends BaseController { public DeferredResult deleteEntityAttributes(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, @PathVariable("scope") String scope, @RequestParam(name = "keys") String keysStr) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return deleteAttributes(entityId, scope, keysStr); + try { + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); + return deleteAttributes(entityId, scope, keysStr); + } catch (Exception e) { + throw handleException(e); + } } private DeferredResult deleteAttributes(EntityId entityIdSrc, String scope, String keysStr) throws ThingsboardException { diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java index 225cfc9097..e656dc1d88 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java @@ -34,13 +34,10 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.msg.tools.TbRateLimitsException; -import org.thingsboard.server.dao.exception.DataValidationException; -import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; import org.thingsboard.server.service.security.exception.JwtExpiredTokenException; import org.thingsboard.server.service.security.exception.UserPasswordExpiredException; -import javax.mail.MessagingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -74,17 +71,6 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand try { response.setContentType(MediaType.APPLICATION_JSON_VALUE); - String cause = ""; - if (exception.getCause() != null) { - cause = exception.getCause().getClass().getCanonicalName(); - } - if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException - || exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { - exception = new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); - } else if (exception instanceof MessagingException) { - exception = new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); - } - if (exception instanceof ThingsboardException) { ThingsboardException thingsboardException = (ThingsboardException) exception; if (thingsboardException.getErrorCode() == ThingsboardErrorCode.SUBSCRIPTION_VIOLATION) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java index 468b409c3e..59fad42fc7 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java @@ -35,6 +35,7 @@ public class WidgetsBundle extends SearchTextBased implements H private String title; private String image; @NoXss + @Length(fieldName = "description") private String description; public WidgetsBundle() { From 30c43812cb1abe68faff93fb94e96eba1df6c6f6 Mon Sep 17 00:00:00 2001 From: Swoq Date: Thu, 2 Sep 2021 17:23:58 +0300 Subject: [PATCH 019/303] Test typo fix --- .../thingsboard/server/controller/BaseUserControllerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java index 7e378ea2dd..e25b5e35ad 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java @@ -121,7 +121,7 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { user.setEmail(email); user.setFirstName(RandomStringUtils.randomAlphabetic(300)); user.setLastName("Downs"); - doPost("/api/user", user).andExpect(statusReason(containsString("Validation error: length of firs name must be equal or less than 255"))); + doPost("/api/user", user).andExpect(statusReason(containsString("Validation error: length of first name must be equal or less than 255"))); user.setFirstName("Normal name"); user.setLastName(RandomStringUtils.randomAlphabetic(300)); doPost("/api/user", user).andExpect(statusReason(containsString("length of last name must be equal or less than 255"))); From 9d3fe774f942390c5a1003d33a0b0598841b3858 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Tue, 7 Sep 2021 16:06:03 +0300 Subject: [PATCH 020/303] Add default property empty array to dataKeySchema and add case to updateWidgetData --- .../main/data/json/system/widget_bundles/input_widgets.json | 2 +- .../components/widget/lib/multiple-input-widget.component.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_bundles/input_widgets.json b/application/src/main/data/json/system/widget_bundles/input_widgets.json index 8651f6e75e..775b1a6260 100644 --- a/application/src/main/data/json/system/widget_bundles/input_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/input_widgets.json @@ -38,7 +38,7 @@ "templateCss": ".tb-toast {\n min-width: 0;\n font-size: 14px !important;\n}", "controllerScript": "self.onInit = function() {\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n self.ctx.$scope.multipleInputWidget.onDataUpdated();\r\n}\r\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"MultipleInput\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showActionButtons\":{\n \"title\":\"Show action buttons\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"updateAllValues\": {\n \"title\":\"Update all values, not only modified\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"saveButtonLabel\": {\n \"title\": \"'SAVE' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"resetButtonLabel\": {\n \"title\": \"'UNDO' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"showGroupTitle\": {\n \"title\":\"Show title for group of fields, related to different entities\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"groupTitle\": {\n \"title\": \"Group title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"fieldsAlignment\": {\n \"title\": \"Fields alignment\",\n \"type\": \"string\",\n \"default\": \"row\"\n },\n \"fieldsInRow\": {\n \"title\": \"Number of fields in the row\",\n \"type\": \"number\",\n \"default\": \"2\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showActionButtons\",\n {\n \"key\": \"updateAllValues\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"saveButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"resetButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n \"showResultMessage\",\n \"showGroupTitle\",\n \"groupTitle\",\n {\n \"key\": \"fieldsAlignment\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"row\",\n \"label\": \"Row (default)\"\n },\n {\n \"value\": \"column\",\n \"label\": \"Column\"\n }\n ]\n },\n {\n \"key\": \"fieldsInRow\",\n \"condition\": \"model.fieldsAlignment === 'row'\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"selectOptions\": {\n \"title\": \"Select options\",\n \"type\": \"array\",\n \"items\": {\n \"title\": \"Option\",\n \"type\": \"object\",\n \"properties\": {\n \"value\": {\n \"title\": \"Value (write 'null' for create empty option)\",\n \"type\": \"string\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"value\"]\n }\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n },\n {\n \"value\": \"select\",\n \"label\": \"Select\"\n }\n ]\n },\n {\n \"key\": \"selectOptions\",\n \"condition\": \"model.dataKeyValueType === 'select'\"\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"selectOptions\": {\n \"title\": \"Select options\",\n \"type\": \"array\",\n \"default\": [],\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"value\": {\n \"title\": \"Value (write 'null' for create empty option)\",\n \"type\": \"string\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"value\"]\n }\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n },\n {\n \"value\": \"select\",\n \"label\": \"Select\"\n }\n ]\n },\n {\n \"key\": \"selectOptions\",\n \"condition\": \"model.dataKeyValueType === 'select'\",\n \"items\": [\"selectOptions[].value\", \"selectOptions[].label\"]\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update Multiple Attributes\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" } }, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index f7c681135e..e4ebd1447c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -355,6 +355,9 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni case 'booleanSwitch': value = (keyData[0][1] === 'true'); break; + case 'select': + value = keyData[0][1].toString(); + break; default: value = keyData[0][1]; } From 18a57bcefc0f7b7707ffbd2f1b258cd68bbc5378 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Tue, 7 Sep 2021 18:01:37 +0300 Subject: [PATCH 021/303] fixed save required field with disabled showActionButton --- .../components/widget/lib/multiple-input-widget.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index e4ebd1447c..fcf1949920 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -24,7 +24,7 @@ import { UtilsService } from '@core/services/utils.service'; import { TranslateService } from '@ngx-translate/core'; import { DataKey, Datasource, DatasourceData, DatasourceType, WidgetConfig } from '@shared/models/widget.models'; import { IWidgetSubscription } from '@core/api/widget-api.models'; -import { createLabelFromDatasource, isDefined, isDefinedAndNotNull, isEqual, isUndefined } from '@core/utils'; +import { createLabelFromDatasource, isDefinedAndNotNull, isEqual, isNotEmptyStr, isUndefined } from '@core/utils'; import { EntityType } from '@shared/models/entity-type.models'; import * as _moment from 'moment'; import { FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; @@ -488,7 +488,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni public inputChanged(source: MultipleInputWidgetSource, key: MultipleInputWidgetDataKey) { if (!this.settings.showActionButtons) { const currentValue = this.multipleInputFormGroup.get(key.formId).value; - if (!key.settings.required || (key.settings.required && isDefined(currentValue))) { + if (!key.settings.required || (key.settings.required && isDefinedAndNotNull(currentValue) && isNotEmptyStr(currentValue.toString()))) { const dataToSave: MultipleInputWidgetSource = { datasource: source.datasource, keys: [key] From bbea48215e33fb4aadf593ecfbe2e02c1f0c2493 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 17 Sep 2021 17:07:58 +0300 Subject: [PATCH 022/303] Changed logic for processing boundary values and change labels --- .../widget/lib/canvas-digital-gauge.ts | 17 +++++++++-------- .../widget/lib/digital-gauge.models.ts | 15 +++++++++------ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts index 898ceb3b81..2665d6a864 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts @@ -466,9 +466,9 @@ export class CanvasDigitalGauge extends BaseGauge { const progress = (Drawings.normalizedValue(options).normal - options.minValue) / (options.maxValue - options.minValue); if (options.neonGlowBrightness) { - color = getProgressColor(progress, options.neonColorsRange); + color = getProgressColor(progress, options.neonColorsRange, options.neonColorValue); } else { - color = getProgressColor(progress, options.colorsRange); + color = getProgressColor(progress, options.colorsRange, options.neonColorValue); } } return color; @@ -814,14 +814,14 @@ function drawDigitalValue(context: DigitalGaugeCanvasRenderingContext2D, options drawText(context, options, 'Value', text, textX, textY); } -function getProgressColor(progress: number, colorsRange: DigitalGaugeColorRange[]): string { +function getProgressColor(progress: number, colorsRange: DigitalGaugeColorRange[], defaultColor: string): string { if (progress === 0 || colorsRange.length === 1) { - return colorsRange[0].rgbString; + return defaultColor; } - for (let j = 0; j < colorsRange.length; j++) { - if (progress <= colorsRange[j].pct) { + for (let j = 1; j < colorsRange.length; j += 2) { + if (progress >= colorsRange[j - 1].pct && progress <= colorsRange[j].pct) { const lower = colorsRange[j - 1]; const upper = colorsRange[j]; const range = upper.pct - lower.pct; @@ -836,6 +836,7 @@ function getProgressColor(progress: number, colorsRange: DigitalGaugeColorRange[ return color.toRgbString(); } } + return defaultColor; } function drawArcGlow(context: DigitalGaugeCanvasRenderingContext2D, @@ -945,9 +946,9 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions, progress: number) { let neonColor; if (options.neonGlowBrightness) { - context.currentColor = neonColor = getProgressColor(progress, options.neonColorsRange); + context.currentColor = neonColor = getProgressColor(progress, options.neonColorsRange, options.neonColorValue); } else { - context.currentColor = context.strokeStyle = getProgressColor(progress, options.colorsRange); + context.currentColor = context.strokeStyle = getProgressColor(progress, options.colorsRange, options.neonColorValue); } const {barLeft, barRight, barTop, baseX, width, barBottom, Cx, Cy, Rm, Ro, Ri, strokeWidth} = diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts index 0897d7a8eb..3cf768668d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts @@ -190,7 +190,7 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { } }, fixedLevelColors: { - title: 'The colors for the indicator using boundary values', + title: 'The colors for the indicator using boundary values in percents', type: 'array', items: { title: 'levelColor', @@ -214,8 +214,9 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { type: 'string' }, value: { - title: '[From] Value (if predefined value is selected)', - type: 'number' + title: '[From] Value, % (if predefined value is selected)', + type: 'number', + default: 0 } } }, @@ -237,8 +238,9 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { type: 'string' }, value: { - title: '[To] Value (if predefined value is selected)', - type: 'number' + title: '[To] Value, % (if predefined value is selected)', + type: 'number', + default: 100 } } }, @@ -246,7 +248,8 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { title: 'Color', type: 'string' } - } + }, + required: ['color'], } }, showTicks: { From 7e91f2c5e2a1bed14b3d857c9645d462b67a947f Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 22 Sep 2021 13:39:23 +0300 Subject: [PATCH 023/303] fix loop and remove default color --- .../widget/lib/canvas-digital-gauge.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts index 2665d6a864..6d1a1f8b8a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts @@ -466,9 +466,9 @@ export class CanvasDigitalGauge extends BaseGauge { const progress = (Drawings.normalizedValue(options).normal - options.minValue) / (options.maxValue - options.minValue); if (options.neonGlowBrightness) { - color = getProgressColor(progress, options.neonColorsRange, options.neonColorValue); + color = getProgressColor(progress, options.neonColorsRange); } else { - color = getProgressColor(progress, options.colorsRange, options.neonColorValue); + color = getProgressColor(progress, options.colorsRange); } } return color; @@ -814,14 +814,14 @@ function drawDigitalValue(context: DigitalGaugeCanvasRenderingContext2D, options drawText(context, options, 'Value', text, textX, textY); } -function getProgressColor(progress: number, colorsRange: DigitalGaugeColorRange[], defaultColor: string): string { +function getProgressColor(progress: number, colorsRange: DigitalGaugeColorRange[]): string { if (progress === 0 || colorsRange.length === 1) { - return defaultColor; + return colorsRange[0].rgbString; } - for (let j = 1; j < colorsRange.length; j += 2) { - if (progress >= colorsRange[j - 1].pct && progress <= colorsRange[j].pct) { + for (let j = 1; j < colorsRange.length; j++) { + if (progress <= colorsRange[j].pct) { const lower = colorsRange[j - 1]; const upper = colorsRange[j]; const range = upper.pct - lower.pct; @@ -836,7 +836,6 @@ function getProgressColor(progress: number, colorsRange: DigitalGaugeColorRange[ return color.toRgbString(); } } - return defaultColor; } function drawArcGlow(context: DigitalGaugeCanvasRenderingContext2D, @@ -946,9 +945,9 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions, progress: number) { let neonColor; if (options.neonGlowBrightness) { - context.currentColor = neonColor = getProgressColor(progress, options.neonColorsRange, options.neonColorValue); + context.currentColor = neonColor = getProgressColor(progress, options.neonColorsRange); } else { - context.currentColor = context.strokeStyle = getProgressColor(progress, options.colorsRange, options.neonColorValue); + context.currentColor = context.strokeStyle = getProgressColor(progress, options.colorsRange); } const {barLeft, barRight, barTop, baseX, width, barBottom, Cx, Cy, Rm, Ro, Ri, strokeWidth} = From a83f328092cd6fa47fd04f7c1c40de98aa3b81ad Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 23 Sep 2021 18:15:29 +0300 Subject: [PATCH 024/303] Add default color for correct work gradient --- .../home/components/widget/lib/canvas-digital-gauge.ts | 2 +- .../app/modules/home/components/widget/lib/digital-gauge.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts index 6d1a1f8b8a..ff896ecaed 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts @@ -276,7 +276,6 @@ export class CanvasDigitalGauge extends BaseGauge { } } } - options.ticksValue = []; for (const tick of options.ticks) { if (tick !== null) { @@ -836,6 +835,7 @@ function getProgressColor(progress: number, colorsRange: DigitalGaugeColorRange[ return color.toRgbString(); } } + return colorsRange[colorsRange.length - 1].rgbString; } function drawArcGlow(context: DigitalGaugeCanvasRenderingContext2D, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts index 8791cd4e93..e82eb7ab29 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts @@ -266,7 +266,6 @@ export class TbCanvasDigitalGauge { init() { let updateSetting = false; - if (this.localSettings.useFixedLevelColor && this.localSettings.fixedLevelColors?.length > 0) { this.localSettings.levelColors = this.settingLevelColorsSubscribe(this.localSettings.fixedLevelColors); updateSetting = true; @@ -285,6 +284,11 @@ export class TbCanvasDigitalGauge { let levelColorsDatasource: Datasource[] = []; const predefineLevelColors: ColorLevelSetting[] = []; + predefineLevelColors.push({ + value: -Infinity, + color: this.ctx.data[0].dataKey.color + }); + function setLevelColor(levelSetting: AttributeSourceProperty, color: string) { if (levelSetting.valueSource === 'predefinedValue' && isFinite(levelSetting.value)) { predefineLevelColors.push({ From b96dd3e78b88f7fda1c0a7e5f4ae7b0c33debbbb Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Mon, 27 Sep 2021 11:49:15 +0300 Subject: [PATCH 025/303] Change infinity value to min value and change color to corect default color --- .../home/components/widget/lib/digital-gauge.models.ts | 6 +++--- .../app/modules/home/components/widget/lib/digital-gauge.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts index 3cf768668d..cb07183415 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts @@ -190,7 +190,7 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { } }, fixedLevelColors: { - title: 'The colors for the indicator using boundary values in percents', + title: 'The colors for the indicator using boundary values', type: 'array', items: { title: 'levelColor', @@ -214,7 +214,7 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { type: 'string' }, value: { - title: '[From] Value, % (if predefined value is selected)', + title: '[From] Value (if predefined value is selected)', type: 'number', default: 0 } @@ -238,7 +238,7 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { type: 'string' }, value: { - title: '[To] Value, % (if predefined value is selected)', + title: '[To] Value (if predefined value is selected)', type: 'number', default: 100 } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts index e82eb7ab29..190cb1bcd7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts @@ -285,8 +285,8 @@ export class TbCanvasDigitalGauge { const predefineLevelColors: ColorLevelSetting[] = []; predefineLevelColors.push({ - value: -Infinity, - color: this.ctx.data[0].dataKey.color + value: this.localSettings.minValue, + color: this.localSettings.gaugeColor }); function setLevelColor(levelSetting: AttributeSourceProperty, color: string) { From 29ac723763210c23628e356ebd75b04b45b42d13 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Mon, 27 Sep 2021 11:53:12 +0300 Subject: [PATCH 026/303] Remove default value from boundary range --- .../home/components/widget/lib/digital-gauge.models.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts index cb07183415..c115f23dbe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.models.ts @@ -215,8 +215,7 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { }, value: { title: '[From] Value (if predefined value is selected)', - type: 'number', - default: 0 + type: 'number' } } }, @@ -239,8 +238,7 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { }, value: { title: '[To] Value (if predefined value is selected)', - type: 'number', - default: 100 + type: 'number' } } }, From ef90332998e03e685659f6b02db892b18535b221 Mon Sep 17 00:00:00 2001 From: Matt Magoffin Date: Thu, 30 Sep 2021 18:11:17 +1300 Subject: [PATCH 027/303] Add option for HTTP client rule node to not create any message body, for example on a DELETE request where technically a body is allowed but the receiving server disallows any body content. --- .../java/org/thingsboard/rule/engine/rest/TbHttpClient.java | 3 ++- .../rule/engine/rest/TbRestApiCallNodeConfiguration.java | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 76f10ebb0c..53d94ffb46 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -176,7 +176,8 @@ public class TbHttpClient { HttpMethod method = HttpMethod.valueOf(config.getRequestMethod()); HttpEntity entity; if(HttpMethod.GET.equals(method) || HttpMethod.HEAD.equals(method) || - HttpMethod.OPTIONS.equals(method) || HttpMethod.TRACE.equals(method)) { + HttpMethod.OPTIONS.equals(method) || HttpMethod.TRACE.equals(method) || + config.isIgnoreRequestBody()) { entity = new HttpEntity<>(headers); } else { entity = new HttpEntity<>(msg.getData(), headers); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java index a357efec31..984c6d9972 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java @@ -47,6 +47,7 @@ public class TbRestApiCallNodeConfiguration implements NodeConfiguration Date: Thu, 30 Sep 2021 16:45:57 +0300 Subject: [PATCH 028/303] Fixed attribute tables pagination on switch between attributes scope --- .../home/components/attribute/attribute-table.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index 5694cc5c77..bcb9edd07e 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -198,6 +198,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI attributeScopeChanged(attributeScope: TelemetryType) { this.attributeScope = attributeScope; this.mode = 'default'; + this.paginator.pageIndex = 0; this.updateData(true); } @@ -447,7 +448,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI if (this.mode === 'widget') { this.widgetsList = []; this.widgetsListCache = []; - this.widgetsCarouselIndex = 0; + this.widgetsCarouselIndex = 0; if (widgetsBundle) { this.widgetsLoaded = false; const bundleAlias = widgetsBundle.alias; From 7077a81d61e537e60a08d29786d1979328177ead Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 30 Sep 2021 16:49:38 +0300 Subject: [PATCH 029/303] Fixed entities table loading first page pagination if time window was changed --- .../modules/home/components/entity/entities-table.component.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index 84c421c5c1..49386db131 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -432,6 +432,9 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn } onTimewindowChange() { + if (this.displayPagination) { + this.paginator.pageIndex = 0; + } this.updateData(); } From 4cb3319f1dce319806d37caeb71ffc3e9c50add1 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 30 Sep 2021 17:40:21 +0300 Subject: [PATCH 030/303] Fixed reltions table pagination when switch direction --- .../modules/home/components/relation/relation-table.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts index cd88d9fae0..b10ed82249 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts @@ -124,6 +124,7 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn directionChanged(direction: EntitySearchDirection) { this.direction = direction; this.updateColumns(); + this.paginator.pageIndex = 0; this.updateData(true); } From 5e84478dd9bc928f8ee272e5bc97c1b0be5d760f Mon Sep 17 00:00:00 2001 From: Matt Magoffin Date: Fri, 1 Oct 2021 10:22:21 +1300 Subject: [PATCH 031/303] Update rule node configuration UI per thingsboard-rule-config-ui-ngx#50 to provide UI toggle for the new ignoreRequestBody HTTP Client rule node option. --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3343ee8cac..721c58dcaf 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 @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
"}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,z=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var Q,_=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Q||(Q={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=_,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(Q),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=z,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(z.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(z.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),Qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[Qe,_e,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[Qe,_e,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,ze,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=ze,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=Qe,e.ɵci=_e,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
"}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,z=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var Q,_=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Q||(Q={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=_,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(Q),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=z,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(z.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(z.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),Qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[Qe,_e,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[Qe,_e,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,ze,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=ze,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=Qe,e.ɵci=_e,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 95c85daefee956e74e5bb91b1d1ef35a89ebfad8 Mon Sep 17 00:00:00 2001 From: Matt Magoffin Date: Sat, 2 Oct 2021 10:21:48 +1300 Subject: [PATCH 032/303] Update rule node configuration UI to latest per thingsboard-rule-config-ui-ngx#50 to provide UI toggle for the new ignoreRequestBody HTTP Client rule node option. --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 721c58dcaf..26cafb63aa 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 @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
"}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,z=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var Q,_=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Q||(Q={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=_,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(Q),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=z,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(z.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(z.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),Qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[Qe,_e,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[Qe,_e,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,ze,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=ze,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=Qe,e.ɵci=_e,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
"}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,z=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var Q,_=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Q||(Q={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=_,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(Q),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=z,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(z.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(z.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),Qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[Qe,_e,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[Qe,_e,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,ze,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=ze,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=Qe,e.ɵci=_e,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 88017dbd90a4b2135fe1b54e4afee2fe788c5967 Mon Sep 17 00:00:00 2001 From: Matt Magoffin Date: Sat, 2 Oct 2021 11:00:02 +1300 Subject: [PATCH 033/303] Add test case for new ignoreRequestBody configuration in TbRestApiCallNode. --- .../engine/rest/TbRestApiCallNodeTest.java | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java new file mode 100644 index 0000000000..a7b82fcf0c --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java @@ -0,0 +1,223 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.rest; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.http.Header; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.config.SocketConfig; +import org.apache.http.impl.bootstrap.HttpServer; +import org.apache.http.impl.bootstrap.ServerBootstrap; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbEmail; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.databind.ObjectMapper; + +@RunWith(MockitoJUnitRunner.class) +public class TbRestApiCallNodeTest { + + private TbRestApiCallNode restNode; + + @Mock + private TbContext ctx; + + private EntityId originator = new DeviceId(Uuids.timeBased()); + private TbMsgMetaData metaData = new TbMsgMetaData(); + + private RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); + + private HttpServer server; + + public void setupServer(String pattern, HttpRequestHandler handler) throws IOException { + SocketConfig config = SocketConfig.custom().setSoReuseAddress(true).setTcpNoDelay(true).build(); + server = ServerBootstrap.bootstrap() + .setSocketConfig(config) + .registerHandler(pattern, handler) + .create(); + server.start(); + } + + private void initWithConfig(TbRestApiCallNodeConfiguration config) { + try { + ObjectMapper mapper = new ObjectMapper(); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + restNode = new TbRestApiCallNode(); + restNode.init(ctx, nodeConfiguration); + } catch (TbNodeException ex) { + throw new IllegalStateException(ex); + } + } + + @After + public void teardown() { + server.stop(); + } + + @Test + public void deleteRequestWithoutBody() throws IOException, InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final String path = "/path/to/delete"; + setupServer("*", new HttpRequestHandler() { + + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + try { + assertEquals("Request path matches", request.getRequestLine().getUri(), path); + assertFalse("Content-Type not included", request.containsHeader("Content-Type")); + assertTrue("Custom header included", request.containsHeader("Foo")); + assertEquals("Custom header value", "Bar", request.getFirstHeader("Foo").getValue()); + response.setStatusCode(200); + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000L); + } catch (InterruptedException e) { + // ignore + } finally { + latch.countDown(); + } + } + }).start(); + } catch ( Exception e ) { + System.out.println("Exception handling request: " + e.toString()); + e.printStackTrace(); + latch.countDown(); + } + } + }); + + TbRestApiCallNodeConfiguration config = new TbRestApiCallNodeConfiguration().defaultConfiguration(); + config.setRequestMethod("DELETE"); + config.setHeaders(Collections.singletonMap("Foo", "Bar")); + config.setIgnoreRequestBody(true); + config.setRestEndpointUrlPattern(String.format("http://localhost:%d%s", server.getLocalPort(), path)); + initWithConfig(config); + + TbMsg msg = TbMsg.newMsg( "USER", originator, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + restNode.onMsg(ctx, msg); + + assertTrue("Server handled request", latch.await(10, TimeUnit.SECONDS)); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); + ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); + verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); + + + assertEquals("USER", typeCaptor.getValue()); + assertEquals(originator, originatorCaptor.getValue()); + assertNotSame(metaData, metadataCaptor.getValue()); + assertEquals("{}", dataCaptor.getValue()); + } + + @Test + public void deleteRequestWithBody() throws IOException, InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final String path = "/path/to/delete"; + setupServer("*", new HttpRequestHandler() { + + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + try { + assertEquals("Request path matches", path, request.getRequestLine().getUri()); + assertTrue("Content-Type included", request.containsHeader("Content-Type")); + assertEquals("Content-Type value", "text/plain;charset=ISO-8859-1", + request.getFirstHeader("Content-Type").getValue()); + assertTrue("Content-Length included", request.containsHeader("Content-Length")); + assertEquals("Content-Length value", "2", + request.getFirstHeader("Content-Length").getValue()); + assertTrue("Custom header included", request.containsHeader("Foo")); + assertEquals("Custom header value", "Bar", request.getFirstHeader("Foo").getValue()); + response.setStatusCode(200); + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000L); + } catch (InterruptedException e) { + // ignore + } finally { + latch.countDown(); + } + } + }).start(); + } catch ( Exception e ) { + System.out.println("Exception handling request: " + e.toString()); + e.printStackTrace(); + latch.countDown(); + } + } + }); + + TbRestApiCallNodeConfiguration config = new TbRestApiCallNodeConfiguration().defaultConfiguration(); + config.setRequestMethod("DELETE"); + config.setHeaders(Collections.singletonMap("Foo", "Bar")); + config.setIgnoreRequestBody(false); + config.setRestEndpointUrlPattern(String.format("http://localhost:%d%s", server.getLocalPort(), path)); + initWithConfig(config); + + TbMsg msg = TbMsg.newMsg( "USER", originator, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + restNode.onMsg(ctx, msg); + + assertTrue("Server handled request", latch.await(10, TimeUnit.SECONDS)); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); + ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); + verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); + + assertEquals("USER", typeCaptor.getValue()); + assertEquals(originator, originatorCaptor.getValue()); + assertNotSame(metaData, metadataCaptor.getValue()); + assertEquals("{}", dataCaptor.getValue()); + } + +} From f12bac3b6c8b36d8e30397419cb1553a3ea01d14 Mon Sep 17 00:00:00 2001 From: Mariesnlk Date: Wed, 6 Oct 2021 17:46:36 +0300 Subject: [PATCH 034/303] add swagger docs to telemetry controller --- .../controller/TelemetryController.java | 125 ++++++++++++------ 1 file changed, 82 insertions(+), 43 deletions(-) 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 d311cdbfed..d206fb276c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2021 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 - * + *

+ * 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. @@ -26,6 +26,8 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -133,83 +135,101 @@ public class TelemetryController extends BaseController { } } + @ApiOperation(value = "Get all existed attributes of entity by it`s type", + notes = "Returns key`s name of the attribute") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributeKeys( - @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { + @ApiParam(value = "A string value representing the entity type. For example, 'ASSET'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the entity id of the required entity type. For example, '87b2fe90-2050-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); } + @ApiOperation(value = "Get all existed attributes of entity by type and scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributeKeysByScope( - @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr - , @PathVariable("scope") String scope) throws ThingsboardException { + @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the scope. For example, 'SERVER_SCOPE'. In the result will be return all server attributes") @PathVariable("scope") String scope) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); } + @ApiOperation(value = "Get all existed attributes of entity by it`s type", + notes = "Returns key and value of the attribute") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributes( - @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { + @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); } + @ApiOperation(value = "Get all existed attributes of entity by it`s type and scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes/{scope}", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributesByScope( - @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @PathVariable("scope") String scope, - @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { + @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the entity type. For example, 'SERVER_SCOPE'") @PathVariable("scope") String scope, + @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); } + @ApiOperation(value = "Get all timeseries keys of entity", + notes = "Return all keys of timeseries of entity id and type") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/timeseries", method = RequestMethod.GET) @ResponseBody public DeferredResult getTimeseriesKeys( - @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { + @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); } + @ApiOperation(value = "Get all last timeseries of entity", + notes = "Return all last timeserie(last time updated or created) of entity id and type") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET) @ResponseBody public DeferredResult getLatestTimeseries( - @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @RequestParam(name = "keys", required = false) String keysStr, - @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { + @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys", required = false) String keysStr, + @ApiParam(value = "A boolean value representing if value of timeseries is representing as a string (by default) or as original type") @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); } - + @ApiOperation(value = "Get all last timeseries of entity", + notes = "Return all timeseries of entity in selected period of time. Based on this information can be built " + + "widget on the dashboard to see updated telemetry in real-time") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"}) @ResponseBody public DeferredResult getTimeseries( - @PathVariable("entityType") String entityType, - @PathVariable("entityId") String entityIdStr, - @RequestParam(name = "keys") String keys, - @RequestParam(name = "startTs") Long startTs, - @RequestParam(name = "endTs") Long endTs, - @RequestParam(name = "interval", defaultValue = "0") Long interval, + @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys") String keys, + @ApiParam(value = "A string value representing the start point of time") @RequestParam(name = "startTs") Long startTs, + @ApiParam(value = "A string value representing the end point of time") @RequestParam(name = "endTs") Long endTs, + @ApiParam(value = "A long value representing the period of time") @RequestParam(name = "interval", defaultValue = "0") Long interval, @RequestParam(name = "limit", defaultValue = "100") Integer limit, - @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, - @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, + @ApiParam(value = "A string value representing the function. For example, 'AVG'") @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, + @ApiParam(value = "A string value representing a sorting type") @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> { @@ -222,25 +242,33 @@ public class TelemetryController extends BaseController { }); } + @ApiOperation(value = "Create and save attribute of device") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.POST) @ResponseBody - public DeferredResult saveDeviceAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope, - @RequestBody JsonNode request) throws ThingsboardException { + public DeferredResult saveDeviceAttributes( + @ApiParam(value = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("deviceId") String deviceIdStr, + @ApiParam(value = "A string value representing the entity type. For example, 'SERVER_SCOPE'") @PathVariable("scope") String scope, + @ApiParam(value = "A string value representing the json object. Should contains key and value of the attribute. For example, '{\"key\":\"value\"}'") @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } + @ApiOperation(value = "Create and save attribute of entity") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.POST) @ResponseBody - public DeferredResult saveEntityAttributesV1(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @PathVariable("scope") String scope, - @RequestBody JsonNode request) throws ThingsboardException { + public DeferredResult saveEntityAttributesV1( + @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the entity id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the entity type. For example, 'SHARED_SCOPE'") @PathVariable("scope") String scope, + @ApiParam(value = "A string value representing the json object. Should contains key and value of the attribute. For example, '{\"key\":\"value\"}'") @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } + @ApiOperation(value = "Create and save attribute of entity", + notes = "The same as saveEntityAttributesV1") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/attributes/{scope}", method = RequestMethod.POST) @ResponseBody @@ -251,35 +279,47 @@ public class TelemetryController extends BaseController { return saveAttributes(getTenantId(), entityId, scope, request); } + @ApiOperation(value = "Save telemetry of entity type and scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}", method = RequestMethod.POST) @ResponseBody - public DeferredResult saveEntityTelemetry(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @PathVariable("scope") String scope, - @RequestBody String requestBody) throws ThingsboardException { + public DeferredResult saveEntityTelemetry( + @ApiParam(value = "A string value representing the device type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the scope. For example, 'SERVER_SCOPE'") @PathVariable("scope") String scope, + @ApiParam(value = "A string value representing the json object. Should contains key and value of the attribute. For example, '{\"key\":\"value\"}'") @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, 0L); } + @ApiOperation(value = "Save telemetry of entity type and scope", + notes = "The TTL parameter is used to extract the number of days to store the data.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}/{ttl}", method = RequestMethod.POST) @ResponseBody - public DeferredResult saveEntityTelemetryWithTTL(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @PathVariable("scope") String scope, @PathVariable("ttl") Long ttl, - @RequestBody String requestBody) throws ThingsboardException { + public DeferredResult saveEntityTelemetryWithTTL( + @ApiParam(value = "A string value representing the device type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the scope. For example, 'SERVER_SCOPE'") @PathVariable("scope") String scope, + @ApiParam(value = "A long value representing the amount of days.") @PathVariable("ttl") Long ttl, + @ApiParam(value = "A string value representing the json object. Should contains key and value of the attribute. For example, '{\"key\":\"value\"}'") @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, ttl); } + @ApiOperation(value = "Delete entity timeseries", + notes = "Delete all timeseries of entity in the required period of time") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/delete", method = RequestMethod.DELETE) @ResponseBody - public DeferredResult deleteEntityTimeseries(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @RequestParam(name = "keys") String keysStr, - @RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys, - @RequestParam(name = "startTs", required = false) Long startTs, - @RequestParam(name = "endTs", required = false) Long endTs, - @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { + public DeferredResult deleteEntityTimeseries( + @ApiParam(value = "A string value representing the device type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, + @ApiParam(value = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr, + @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys") String keysStr, + @ApiParam(value = "A boolean value representing if should be deleted all data of required key or only the latest") @RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys, + @ApiParam(value = "A long value representing the start point of time") @RequestParam(name = "startTs", required = false) Long startTs, + @ApiParam(value = "A long value representing the end point of time") @RequestParam(name = "endTs", required = false) Long endTs, + @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); } @@ -311,7 +351,6 @@ public class TelemetryController extends BaseController { for (String key : keys) { deleteTsKvQueries.add(new BaseDeleteTsKvQuery(key, deleteFromTs, deleteToTs, rewriteLatestIfDeleted)); } - ListenableFuture> future = tsService.remove(user.getTenantId(), entityId, deleteTsKvQueries); Futures.addCallback(future, new FutureCallback>() { @Override From a098bf0bf902ffa06d60da8ce6de870dfd656459 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 6 Oct 2021 18:05:02 +0300 Subject: [PATCH 035/303] Implement concurrent bulk import processing --- .../server/controller/AssetController.java | 11 +-- .../server/controller/DeviceController.java | 11 +-- .../server/controller/EdgeController.java | 8 +- .../device/DeviceBulkImportService.java | 53 +++++++----- .../importing/AbstractBulkImportService.java | 80 +++++++++++++------ .../service/importing/BulkImportResult.java | 14 ++-- .../service/importing/ImportedEntityInfo.java | 1 - .../thingsboard/common/util/DonAsynchron.java | 12 +++ .../dao/device/DeviceCredentialsDao.java | 2 + .../device/DeviceCredentialsServiceImpl.java | 2 +- .../server/dao/device/DeviceProfileDao.java | 2 + .../dao/device/DeviceProfileServiceImpl.java | 2 +- .../device/DeviceCredentialsRepository.java | 4 +- .../sql/device/DeviceProfileRepository.java | 3 +- .../sql/device/JpaDeviceCredentialsDao.java | 9 +++ .../dao/sql/device/JpaDeviceProfileDao.java | 9 +++ 16 files changed, 152 insertions(+), 71 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index d63674b7ee..a4e1af1da5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -116,7 +116,7 @@ public class AssetController extends BaseController { Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); - onAssetCreatedOrUpdated(savedAsset, asset.getId() != null); + onAssetCreatedOrUpdated(savedAsset, asset.getId() != null, getCurrentUser()); return savedAsset; } catch (Exception e) { @@ -126,9 +126,9 @@ public class AssetController extends BaseController { } } - private void onAssetCreatedOrUpdated(Asset asset, boolean updated) { + private void onAssetCreatedOrUpdated(Asset asset, boolean updated, SecurityUser user) { try { - logEntityAction(asset.getId(), asset, + logEntityAction(user, asset.getId(), asset, asset.getCustomerId(), updated ? ActionType.UPDATED : ActionType.ADDED, null); } catch (ThingsboardException e) { @@ -550,8 +550,9 @@ public class AssetController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PostMapping("/asset/bulk_import") public BulkImportResult processAssetsBulkImport(@RequestBody BulkImportRequest request) throws Exception { - return assetBulkImportService.processBulkImport(request, getCurrentUser(), importedAssetInfo -> { - onAssetCreatedOrUpdated(importedAssetInfo.getEntity(), importedAssetInfo.isUpdated()); + SecurityUser user = getCurrentUser(); + return assetBulkImportService.processBulkImport(request, user, importedAssetInfo -> { + onAssetCreatedOrUpdated(importedAssetInfo.getEntity(), importedAssetInfo.isUpdated(), user); }); } 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 8cfa5ee2cf..fbd03b3067 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -141,7 +141,7 @@ public class DeviceController extends BaseController { Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); - onDeviceCreatedOrUpdated(savedDevice, oldDevice, !created); + onDeviceCreatedOrUpdated(savedDevice, oldDevice, !created, getCurrentUser()); return savedDevice; } catch (Exception e) { @@ -152,11 +152,11 @@ public class DeviceController extends BaseController { } - private void onDeviceCreatedOrUpdated(Device savedDevice, Device oldDevice, boolean updated) { + private void onDeviceCreatedOrUpdated(Device savedDevice, Device oldDevice, boolean updated, SecurityUser user) { tbClusterService.onDeviceUpdated(savedDevice, oldDevice); try { - logEntityAction(savedDevice.getId(), savedDevice, + logEntityAction(user, savedDevice.getId(), savedDevice, savedDevice.getCustomerId(), updated ? ActionType.UPDATED : ActionType.ADDED, null); } catch (ThingsboardException e) { @@ -796,8 +796,9 @@ public class DeviceController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PostMapping("/device/bulk_import") public BulkImportResult processDevicesBulkImport(@RequestBody BulkImportRequest request) throws Exception { - return deviceBulkImportService.processBulkImport(request, getCurrentUser(), importedDeviceInfo -> { - onDeviceCreatedOrUpdated(importedDeviceInfo.getEntity(), importedDeviceInfo.getOldEntity(), importedDeviceInfo.isUpdated()); + SecurityUser user = getCurrentUser(); + return deviceBulkImportService.processBulkImport(request, user, importedDeviceInfo -> { + onDeviceCreatedOrUpdated(importedDeviceInfo.getEntity(), importedDeviceInfo.getOldEntity(), importedDeviceInfo.isUpdated(), user); }); } diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 21c39cdd58..da0e103ad2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -140,7 +140,7 @@ public class EdgeController extends BaseController { edge.getId(), edge); Edge savedEdge = checkNotNull(edgeService.saveEdge(edge, true)); - onEdgeCreatedOrUpdated(tenantId, savedEdge, edgeTemplateRootRuleChain, !created); + onEdgeCreatedOrUpdated(tenantId, savedEdge, edgeTemplateRootRuleChain, !created, getCurrentUser()); return savedEdge; } catch (Exception e) { @@ -150,7 +150,7 @@ public class EdgeController extends BaseController { } } - private void onEdgeCreatedOrUpdated(TenantId tenantId, Edge edge, RuleChain edgeTemplateRootRuleChain, boolean updated) throws IOException, ThingsboardException { + private void onEdgeCreatedOrUpdated(TenantId tenantId, Edge edge, RuleChain edgeTemplateRootRuleChain, boolean updated, SecurityUser user) throws IOException, ThingsboardException { if (!updated) { ruleChainService.assignRuleChainToEdge(tenantId, edgeTemplateRootRuleChain.getId(), edge.getId()); edgeNotificationService.setEdgeRootRuleChain(tenantId, edge, edgeTemplateRootRuleChain.getId()); @@ -160,7 +160,7 @@ public class EdgeController extends BaseController { tbClusterService.broadcastEntityStateChangeEvent(edge.getTenantId(), edge.getId(), updated ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED); - logEntityAction(edge.getId(), edge, null, updated ? ActionType.UPDATED : ActionType.ADDED, null); + logEntityAction(user, edge.getId(), edge, null, updated ? ActionType.UPDATED : ActionType.ADDED, null); } @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -586,7 +586,7 @@ public class EdgeController extends BaseController { return edgeBulkImportService.processBulkImport(request, user, importedAssetInfo -> { try { - onEdgeCreatedOrUpdated(user.getTenantId(), importedAssetInfo.getEntity(), edgeTemplateRootRuleChain, importedAssetInfo.isUpdated()); + onEdgeCreatedOrUpdated(user.getTenantId(), importedAssetInfo.getEntity(), edgeTemplateRootRuleChain, importedAssetInfo.isUpdated(), user); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java index 82d4dc5571..707674f6ba 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java @@ -63,6 +63,8 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; @Service @TbCoreComponent @@ -71,6 +73,8 @@ public class DeviceBulkImportService extends AbstractBulkImportService { protected final DeviceCredentialsService deviceCredentialsService; protected final DeviceProfileService deviceProfileService; + private final Lock findOrCreateDeviceProfileLock = new ReentrantLock(); + public DeviceBulkImportService(TelemetrySubscriptionService tsSubscriptionService, TbTenantProfileCache tenantProfileCache, AccessControlService accessControlService, AccessValidator accessValidator, EntityActionService entityActionService, TbClusterService clusterService, @@ -106,9 +110,13 @@ public class DeviceBulkImportService extends AbstractBulkImportService { throw new DeviceCredentialsValidationException("Invalid device credentials: " + e.getMessage()); } + DeviceProfile deviceProfile; if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { - setUpLwM2mDeviceProfile(user.getTenantId(), device); + deviceProfile = setUpLwM2mDeviceProfile(user.getTenantId(), device); + } else { + deviceProfile = deviceProfileService.findOrCreateDeviceProfile(user.getTenantId(), device.getType()); } + device.setDeviceProfileId(deviceProfile.getId()); device = deviceService.saveDeviceWithCredentials(device, deviceCredentials); @@ -215,36 +223,43 @@ public class DeviceBulkImportService extends AbstractBulkImportService { credentials.setCredentialsValue(lwm2mCredentials.toString()); } - private void setUpLwM2mDeviceProfile(TenantId tenantId, Device device) { + private DeviceProfile setUpLwM2mDeviceProfile(TenantId tenantId, Device device) { DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileByName(tenantId, device.getType()); if (deviceProfile != null) { if (deviceProfile.getTransportType() != DeviceTransportType.LWM2M) { deviceProfile.setTransportType(DeviceTransportType.LWM2M); deviceProfile.getProfileData().setTransportConfiguration(new Lwm2mDeviceProfileTransportConfiguration()); deviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); - device.setDeviceProfileId(deviceProfile.getId()); } } else { - deviceProfile = new DeviceProfile(); - deviceProfile.setTenantId(tenantId); - deviceProfile.setType(DeviceProfileType.DEFAULT); - deviceProfile.setName(device.getType()); - deviceProfile.setTransportType(DeviceTransportType.LWM2M); - deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED); + findOrCreateDeviceProfileLock.lock(); + try { + deviceProfile = deviceProfileService.findDeviceProfileByName(tenantId, device.getType()); + if (deviceProfile == null) { + deviceProfile = new DeviceProfile(); + deviceProfile.setTenantId(tenantId); + deviceProfile.setType(DeviceProfileType.DEFAULT); + deviceProfile.setName(device.getType()); + deviceProfile.setTransportType(DeviceTransportType.LWM2M); + deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED); - DeviceProfileData deviceProfileData = new DeviceProfileData(); - DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); - DeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration(); - DisabledDeviceProfileProvisionConfiguration provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(null); + DeviceProfileData deviceProfileData = new DeviceProfileData(); + DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); + DeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration(); + DisabledDeviceProfileProvisionConfiguration provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(null); - deviceProfileData.setConfiguration(configuration); - deviceProfileData.setTransportConfiguration(transportConfiguration); - deviceProfileData.setProvisionConfiguration(provisionConfiguration); - deviceProfile.setProfileData(deviceProfileData); + deviceProfileData.setConfiguration(configuration); + deviceProfileData.setTransportConfiguration(transportConfiguration); + deviceProfileData.setProvisionConfiguration(provisionConfiguration); + deviceProfile.setProfileData(deviceProfileData); - deviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); - device.setDeviceProfileId(deviceProfile.getId()); + deviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + } + } finally { + findOrCreateDeviceProfileLock.unlock(); + } } + return deviceProfile; } private void setValues(ObjectNode objectNode, Map data, Collection columns) { diff --git a/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java index b1d0b30c9d..a1e3ff16ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java @@ -22,6 +22,9 @@ import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.thingsboard.common.util.DonAsynchron; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.TenantProfile; @@ -47,11 +50,16 @@ import org.thingsboard.server.utils.CsvUtils; import org.thingsboard.server.utils.TypeCastUtil; import javax.annotation.Nullable; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -67,39 +75,49 @@ public abstract class AbstractBulkImportService processBulkImport(BulkImportRequest request, SecurityUser user, Consumer> onEntityImported) throws Exception { - BulkImportResult result = new BulkImportResult<>(); + private static ThreadPoolExecutor executor; - AtomicInteger i = new AtomicInteger(0); - if (request.getMapping().getHeader()) { - i.incrementAndGet(); + @PostConstruct + private void initExecutor() { + if (executor == null) { + executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(), + 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(150_000), + ThingsBoardThreadFactory.forName("bulk-import"), new ThreadPoolExecutor.CallerRunsPolicy()); + executor.allowCoreThreadTimeOut(true); } + } - parseData(request).forEach(entityData -> { - i.incrementAndGet(); - try { - ImportedEntityInfo importedEntityInfo = saveEntity(request, entityData.getFields(), user); - onEntityImported.accept(importedEntityInfo); + public final BulkImportResult processBulkImport(BulkImportRequest request, SecurityUser user, Consumer> onEntityImported) throws Exception { + List entitiesData = parseData(request); - E entity = importedEntityInfo.getEntity(); + BulkImportResult result = new BulkImportResult<>(); + CountDownLatch completionLatch = new CountDownLatch(entitiesData.size()); - saveKvs(user, entity, entityData.getKvs()); + entitiesData.forEach(entityData -> DonAsynchron.submit(() -> { + ImportedEntityInfo importedEntityInfo = saveEntity(request, entityData.getFields(), user); + E entity = importedEntityInfo.getEntity(); - if (importedEntityInfo.getRelatedError() != null) { - throw new RuntimeException(importedEntityInfo.getRelatedError()); - } + onEntityImported.accept(importedEntityInfo); + saveKvs(user, entity, entityData.getKvs()); - if (importedEntityInfo.isUpdated()) { - result.setUpdated(result.getUpdated() + 1); - } else { - result.setCreated(result.getCreated() + 1); - } - } catch (Exception e) { - result.setErrors(result.getErrors() + 1); - result.getErrorsList().add(String.format("Line %d: %s", i.get(), e.getMessage())); - } - }); + return importedEntityInfo; + }, + importedEntityInfo -> { + if (importedEntityInfo.isUpdated()) { + result.getUpdated().incrementAndGet(); + } else { + result.getCreated().incrementAndGet(); + } + completionLatch.countDown(); + }, + throwable -> { + result.getErrors().incrementAndGet(); + result.getErrorsList().add(String.format("Line %d: %s", entityData.getLineNumber(), ExceptionUtils.getRootCauseMessage(throwable))); + completionLatch.countDown(); + }, + executor)); + completionLatch.await(); return result; } @@ -186,8 +204,11 @@ public abstract class AbstractBulkImportService parseData(BulkImportRequest request) throws Exception { List> records = CsvUtils.parseCsv(request.getFile(), request.getMapping().getDelimiter()); + AtomicInteger linesCounter = new AtomicInteger(0); + if (request.getMapping().getHeader()) { records.remove(0); + linesCounter.incrementAndGet(); } List columnsMappings = request.getMapping().getColumns(); @@ -205,15 +226,24 @@ public abstract class AbstractBulkImportService fields = new LinkedHashMap<>(); private final Map kvs = new LinkedHashMap<>(); + private int lineNumber; } @Data diff --git a/application/src/main/java/org/thingsboard/server/service/importing/BulkImportResult.java b/application/src/main/java/org/thingsboard/server/service/importing/BulkImportResult.java index d6fa6ccbf9..7e937d835d 100644 --- a/application/src/main/java/org/thingsboard/server/service/importing/BulkImportResult.java +++ b/application/src/main/java/org/thingsboard/server/service/importing/BulkImportResult.java @@ -17,14 +17,14 @@ package org.thingsboard.server.service.importing; import lombok.Data; -import java.util.LinkedList; -import java.util.List; +import java.util.Collection; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.atomic.AtomicInteger; @Data public class BulkImportResult { - private int created = 0; - private int updated = 0; - private int errors = 0; - private List errorsList = new LinkedList<>(); - + private AtomicInteger created = new AtomicInteger(); + private AtomicInteger updated = new AtomicInteger(); + private AtomicInteger errors = new AtomicInteger(); + private Collection errorsList = new ConcurrentLinkedDeque<>(); } diff --git a/application/src/main/java/org/thingsboard/server/service/importing/ImportedEntityInfo.java b/application/src/main/java/org/thingsboard/server/service/importing/ImportedEntityInfo.java index 958863537a..846444c1d5 100644 --- a/application/src/main/java/org/thingsboard/server/service/importing/ImportedEntityInfo.java +++ b/application/src/main/java/org/thingsboard/server/service/importing/ImportedEntityInfo.java @@ -22,5 +22,4 @@ public class ImportedEntityInfo { private E entity; private boolean isUpdated; private E oldEntity; - private String relatedError; } diff --git a/common/util/src/main/java/org/thingsboard/common/util/DonAsynchron.java b/common/util/src/main/java/org/thingsboard/common/util/DonAsynchron.java index 5480a3bd69..d615890507 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/DonAsynchron.java +++ b/common/util/src/main/java/org/thingsboard/common/util/DonAsynchron.java @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -53,4 +54,15 @@ public class DonAsynchron { Futures.addCallback(future, callback, MoreExecutors.directExecutor()); } } + + public static ListenableFuture submit(Callable task, Consumer onSuccess, Consumer onFailure, Executor executor) { + return submit(task, onSuccess, onFailure, executor, null); + } + + public static ListenableFuture submit(Callable task, Consumer onSuccess, Consumer onFailure, Executor executor, Executor callbackExecutor) { + ListenableFuture future = Futures.submit(task, executor); + withCallback(future, onSuccess, onFailure, callbackExecutor); + return future; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsDao.java index 59ed00052e..7e07347ca4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsDao.java @@ -35,6 +35,8 @@ public interface DeviceCredentialsDao extends Dao { */ DeviceCredentials save(TenantId tenantId, DeviceCredentials deviceCredentials); + DeviceCredentials saveAndFlush(TenantId tenantId, DeviceCredentials deviceCredentials); + /** * Find device credentials by device id. * diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 47af5df8fe..14539066ff 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -96,7 +96,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials); credentialsValidator.validate(deviceCredentials, id -> tenantId); try { - return deviceCredentialsDao.save(tenantId, deviceCredentials); + return deviceCredentialsDao.saveAndFlush(tenantId, deviceCredentials); } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java index 120bf0bad0..2200416e6d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java @@ -30,6 +30,8 @@ public interface DeviceProfileDao extends Dao { DeviceProfile save(TenantId tenantId, DeviceProfile deviceProfile); + DeviceProfile saveAndFlush(TenantId tenantId, DeviceProfile deviceProfile); + PageData findDeviceProfiles(TenantId tenantId, PageLink pageLink); PageData findDeviceProfileInfos(TenantId tenantId, PageLink pageLink, String transportType); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 720d50ad69..105352c8a5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -167,7 +167,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } DeviceProfile savedDeviceProfile; try { - savedDeviceProfile = deviceProfileDao.save(deviceProfile.getTenantId(), deviceProfile); + savedDeviceProfile = deviceProfileDao.saveAndFlush(deviceProfile.getTenantId(), deviceProfile); } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_profile_name_unq_key")) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceCredentialsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceCredentialsRepository.java index 02ae32bd3e..97c9913239 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceCredentialsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceCredentialsRepository.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.dao.sql.device; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.jpa.repository.JpaRepository; import org.thingsboard.server.dao.model.sql.DeviceCredentialsEntity; import java.util.UUID; @@ -23,7 +23,7 @@ import java.util.UUID; /** * Created by Valerii Sosliuk on 5/6/2017. */ -public interface DeviceCredentialsRepository extends CrudRepository { +public interface DeviceCredentialsRepository extends JpaRepository { DeviceCredentialsEntity findByDeviceId(UUID deviceId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java index 1dc2af4ecf..311c73100c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.sql.device; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; @@ -26,7 +27,7 @@ import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; import java.util.UUID; -public interface DeviceProfileRepository extends PagingAndSortingRepository { +public interface DeviceProfileRepository extends JpaRepository { @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.defaultDashboardId, d.type, d.transportType) " + "FROM DeviceProfileEntity d " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceCredentialsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceCredentialsDao.java index 68eb7ab37a..26453a5e52 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceCredentialsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceCredentialsDao.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.sql.device; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.DaoUtil; @@ -46,6 +47,14 @@ public class JpaDeviceCredentialsDao extends JpaAbstractDao findDeviceProfiles(TenantId tenantId, PageLink pageLink) { return DaoUtil.toPageData( From c8ce826b7cc7b7898f7328958bb8d73ed7d469b1 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 7 Oct 2021 12:36:27 +0300 Subject: [PATCH 036/303] Fix pagination on timewindow updated --- ui-ngx/src/app/core/api/widget-subscription.ts | 8 +++++++- .../lib/timeseries-table-widget.component.ts | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 5481af9255..0f05208981 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -67,7 +67,7 @@ import { KeyFilter, updateDatasourceFromEntityInfo } from '@shared/models/query/query.models'; -import { filter, map, switchMap, takeUntil } from 'rxjs/operators'; +import { distinct, filter, map, switchMap, takeUntil } from 'rxjs/operators'; import { AlarmDataListener } from '@core/api/alarm-data.service'; import { RpcStatus } from '@shared/models/rpc.models'; @@ -139,6 +139,11 @@ export class WidgetSubscription implements IWidgetSubscription { executingSubjects: Array>; subscribed = false; + widgetTimewindowChangedSubject: Subject = new ReplaySubject(); + + widgetTimewindowChanged = this.widgetTimewindowChangedSubject.asObservable().pipe( + distinct() + ); constructor(subscriptionContext: WidgetSubscriptionContext, public options: WidgetSubscriptionOptions) { const subscriptionSubject = new ReplaySubject(); @@ -805,6 +810,7 @@ export class WidgetSubscription implements IWidgetSubscription { update(isTimewindowTypeChanged = false) { if (this.type !== widgetType.rpc) { + this.widgetTimewindowChangedSubject.next(this.timeWindowConfig); if (this.type === widgetType.alarm) { this.updateAlarmDataSubscription(); } else { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index 3f36769baf..e22c7b6f1c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -139,6 +139,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI private rowStylesInfo: RowStyleInfo; private subscriptions: Subscription[] = []; + private widgetTimewindowChangedSubscription: Subscription; private searchAction: WidgetAction = { name: 'action.search', @@ -169,6 +170,23 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.datasources = this.ctx.datasources; this.initialize(); this.ctx.updateWidgetParams(); + + this.widgetTimewindowChangedSubscription = this.ctx.defaultSubscription.widgetTimewindowChanged.subscribe( + () => { + this.sources.forEach((source) => { + if (this.displayPagination) { + source.pageLink.page = 0; + } + }); + } + ); + } + + ngOnDestroy(): void { + if (this.widgetTimewindowChangedSubscription) { + this.widgetTimewindowChangedSubscription.unsubscribe(); + this.widgetTimewindowChangedSubscription = null; + } } ngAfterViewInit(): void { From 246390b43b15bb29cb28fcf2146e5f765b475358 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 7 Oct 2021 12:52:42 +0300 Subject: [PATCH 037/303] Fix pagination on alarm table widget after timewindow updated --- .../widget/lib/alarms-table-widget.component.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 390559bab3..deb3083b8f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -48,7 +48,7 @@ import cssjs from '@core/css/css'; import { sortItems } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; import { CollectionViewer, DataSource, SelectionModel } from '@angular/cdk/collections'; -import { BehaviorSubject, forkJoin, fromEvent, merge, Observable } from 'rxjs'; +import { BehaviorSubject, forkJoin, fromEvent, merge, Observable, Subscription } from 'rxjs'; import { emptyPageData, PageData } from '@shared/models/page/page-data'; import { entityTypeTranslations } from '@shared/models/entity-type.models'; import { debounceTime, distinctUntilChanged, map, take, tap } from 'rxjs/operators'; @@ -188,6 +188,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, private rowStylesInfo: RowStyleInfo; + private widgetTimewindowChangedSubscription: Subscription; + private searchAction: WidgetAction = { name: 'action.search', show: true, @@ -243,6 +245,17 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.initializeConfig(); this.updateAlarmSource(); this.ctx.updateWidgetParams(); + + this.widgetTimewindowChangedSubscription = this.ctx.defaultSubscription.widgetTimewindowChanged.subscribe( + () => this.pageLink.page = 0 + ); + } + + ngOnDestroy(): void { + if (this.widgetTimewindowChangedSubscription) { + this.widgetTimewindowChangedSubscription.unsubscribe(); + this.widgetTimewindowChangedSubscription = null; + } } ngAfterViewInit(): void { From 28a2b11faa299e899a244c1d3032fc6d31b28418 Mon Sep 17 00:00:00 2001 From: Mariesnlk Date: Thu, 7 Oct 2021 15:29:37 +0300 Subject: [PATCH 038/303] fix license in telemetry controller --- .../server/controller/TelemetryController.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 d206fb276c..8e3f5c16a7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2021 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 - *

+ * + * 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. From e2b0fd6c155ffa4a2b5488d05a5d9fc518afc521 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 8 Oct 2021 13:05:44 +0300 Subject: [PATCH 039/303] Add compleate to subject and do subscribe if display pagination turn on --- ui-ngx/src/app/core/api/widget-api.models.ts | 4 +++- .../lib/alarms-table-widget.component.ts | 9 +++++--- .../date-range-navigator.component.ts | 1 + .../lib/timeseries-table-widget.component.ts | 21 +++++++++++-------- .../home/models/dashboard-component.models.ts | 1 + 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index 4f46212231..2ed130cc60 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Observable } from 'rxjs'; +import { Observable, Subject } from 'rxjs'; import { EntityId } from '@app/shared/models/id/entity-id'; import { DataSet, @@ -277,6 +277,8 @@ export interface IWidgetSubscription { hiddenData?: Array<{data: DataSet}>; timeWindowConfig?: Timewindow; timeWindow?: WidgetTimewindow; + widgetTimewindowChanged: Observable; + widgetTimewindowChangedSubject: Subject; comparisonEnabled?: boolean; comparisonTimeWindow?: WidgetTimewindow; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index deb3083b8f..4054041c48 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -246,9 +246,11 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.updateAlarmSource(); this.ctx.updateWidgetParams(); - this.widgetTimewindowChangedSubscription = this.ctx.defaultSubscription.widgetTimewindowChanged.subscribe( - () => this.pageLink.page = 0 - ); + if (this.displayPagination) { + this.widgetTimewindowChangedSubscription = this.ctx.defaultSubscription.widgetTimewindowChanged.subscribe( + () => this.pageLink.page = 0 + ); + } } ngOnDestroy(): void { @@ -256,6 +258,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.widgetTimewindowChangedSubscription.unsubscribe(); this.widgetTimewindowChangedSubscription = null; } + this.ctx.defaultSubscription.widgetTimewindowChangedSubject.complete(); } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts index 526913af8d..640e09478c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts @@ -119,6 +119,7 @@ export class DateRangeNavigatorWidgetComponent extends PageComponent implements this.dashboardTimewindowChangedSubscription.unsubscribe(); this.dashboardTimewindowChangedSubscription = null; } + this.ctx.dashboard.dashboardTimewindowChangedSubject.complete(); } openNavigatorPanel($event: Event) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index e22c7b6f1c..5dfd47ed83 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -171,15 +171,17 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.initialize(); this.ctx.updateWidgetParams(); - this.widgetTimewindowChangedSubscription = this.ctx.defaultSubscription.widgetTimewindowChanged.subscribe( - () => { - this.sources.forEach((source) => { - if (this.displayPagination) { - source.pageLink.page = 0; - } - }); - } - ); + if (this.displayPagination) { + this.widgetTimewindowChangedSubscription = this.ctx.defaultSubscription.widgetTimewindowChanged.subscribe( + () => { + this.sources.forEach((source) => { + if (this.displayPagination) { + source.pageLink.page = 0; + } + }); + } + ); + } } ngOnDestroy(): void { @@ -187,6 +189,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.widgetTimewindowChangedSubscription.unsubscribe(); this.widgetTimewindowChangedSubscription = null; } + this.ctx.defaultSubscription.widgetTimewindowChangedSubject.complete(); } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index ffcaef06ef..3ce1779bf6 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -67,6 +67,7 @@ export interface IDashboardComponent { autofillHeight: boolean; dashboardTimewindow: Timewindow; dashboardTimewindowChanged: Observable; + dashboardTimewindowChangedSubject: Subject; aliasController: IAliasController; stateController: IStateController; onUpdateTimewindow(startTimeMs: number, endTimeMs: number, interval?: number, persist?: boolean): void; From 1f44d538ee090c3c73e4772bcbe4f01a186b2bb0 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 8 Oct 2021 13:26:41 +0300 Subject: [PATCH 040/303] Do not send empty alarm updated messages during creation of TS subscriptions --- .../server/service/subscription/TbAlarmDataSubCtx.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java index 893d7ed91c..c3343effb5 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java @@ -177,7 +177,9 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { alarm.getLatest().computeIfAbsent(keyType, tmp -> new HashMap<>()).putAll(latestUpdate); return alarm; }).collect(Collectors.toList()); - wsService.sendWsMsg(sessionId, new AlarmDataUpdate(cmdId, null, update, maxEntitiesPerAlarmSubscription, data.getTotalElements())); + if (!update.isEmpty()) { + wsService.sendWsMsg(sessionId, new AlarmDataUpdate(cmdId, null, update, maxEntitiesPerAlarmSubscription, data.getTotalElements())); + } } else { log.trace("[{}][{}][{}][{}] Received stale subscription update: {}", sessionId, cmdId, subscriptionUpdate.getSubscriptionId(), keyType, subscriptionUpdate); } From c93e661e326682c1c4fce76a8a310b7a184f4cf9 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 8 Oct 2021 16:58:02 +0300 Subject: [PATCH 041/303] Update widget-api.models.ts --- ui-ngx/src/app/core/api/widget-api.models.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index 2ed130cc60..eeeb73d038 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -278,7 +278,6 @@ export interface IWidgetSubscription { timeWindowConfig?: Timewindow; timeWindow?: WidgetTimewindow; widgetTimewindowChanged: Observable; - widgetTimewindowChangedSubject: Subject; comparisonEnabled?: boolean; comparisonTimeWindow?: WidgetTimewindow; From 45961519cdecb465f6cc7507a6c8e5d1627d00bf Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 8 Oct 2021 19:21:03 +0300 Subject: [PATCH 042/303] UI: Refactoring code --- ui-ngx/src/app/core/api/widget-api.models.ts | 4 ++-- ui-ngx/src/app/core/api/widget-subscription.ts | 3 ++- .../home/components/dashboard/dashboard.component.ts | 1 + .../widget/lib/alarms-table-widget.component.ts | 11 +++++------ .../date-range-navigator.component.ts | 1 - .../widget/lib/timeseries-table-widget.component.ts | 11 +++++------ .../modules/home/models/dashboard-component.models.ts | 1 - 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index eeeb73d038..91555a040a 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Observable, Subject } from 'rxjs'; +import { Observable } from 'rxjs'; import { EntityId } from '@app/shared/models/id/entity-id'; import { DataSet, @@ -277,7 +277,7 @@ export interface IWidgetSubscription { hiddenData?: Array<{data: DataSet}>; timeWindowConfig?: Timewindow; timeWindow?: WidgetTimewindow; - widgetTimewindowChanged: Observable; + widgetTimewindowChanged$: Observable; comparisonEnabled?: boolean; comparisonTimeWindow?: WidgetTimewindow; diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 0f05208981..61ada4ffd2 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -141,7 +141,7 @@ export class WidgetSubscription implements IWidgetSubscription { subscribed = false; widgetTimewindowChangedSubject: Subject = new ReplaySubject(); - widgetTimewindowChanged = this.widgetTimewindowChangedSubject.asObservable().pipe( + widgetTimewindowChanged$ = this.widgetTimewindowChangedSubject.asObservable().pipe( distinct() ); @@ -1124,6 +1124,7 @@ export class WidgetSubscription implements IWidgetSubscription { destroy(): void { this.unsubscribe(); + this.widgetTimewindowChangedSubject.complete(); for (const cafId of Object.keys(this.cafs)) { if (this.cafs[cafId]) { this.cafs[cafId](); diff --git a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts index 72c242c308..b7bd51c437 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts @@ -238,6 +238,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo if (this.breakpointObserverSubscription) { this.breakpointObserverSubscription.unsubscribe(); } + this.dashboardTimewindowChangedSubject.complete(); this.gridster = null; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 4054041c48..dd3539024b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -188,7 +188,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, private rowStylesInfo: RowStyleInfo; - private widgetTimewindowChangedSubscription: Subscription; + private widgetTimewindowChanged$: Subscription; private searchAction: WidgetAction = { name: 'action.search', @@ -247,18 +247,17 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.ctx.updateWidgetParams(); if (this.displayPagination) { - this.widgetTimewindowChangedSubscription = this.ctx.defaultSubscription.widgetTimewindowChanged.subscribe( + this.widgetTimewindowChanged$ = this.ctx.defaultSubscription.widgetTimewindowChanged$.subscribe( () => this.pageLink.page = 0 ); } } ngOnDestroy(): void { - if (this.widgetTimewindowChangedSubscription) { - this.widgetTimewindowChangedSubscription.unsubscribe(); - this.widgetTimewindowChangedSubscription = null; + if (this.widgetTimewindowChanged$) { + this.widgetTimewindowChanged$.unsubscribe(); + this.widgetTimewindowChanged$ = null; } - this.ctx.defaultSubscription.widgetTimewindowChangedSubject.complete(); } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts index 640e09478c..526913af8d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts @@ -119,7 +119,6 @@ export class DateRangeNavigatorWidgetComponent extends PageComponent implements this.dashboardTimewindowChangedSubscription.unsubscribe(); this.dashboardTimewindowChangedSubscription = null; } - this.ctx.dashboard.dashboardTimewindowChangedSubject.complete(); } openNavigatorPanel($event: Event) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index 5dfd47ed83..f5b01ef39a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -139,7 +139,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI private rowStylesInfo: RowStyleInfo; private subscriptions: Subscription[] = []; - private widgetTimewindowChangedSubscription: Subscription; + private widgetTimewindowChanged$: Subscription; private searchAction: WidgetAction = { name: 'action.search', @@ -172,7 +172,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.ctx.updateWidgetParams(); if (this.displayPagination) { - this.widgetTimewindowChangedSubscription = this.ctx.defaultSubscription.widgetTimewindowChanged.subscribe( + this.widgetTimewindowChanged$ = this.ctx.defaultSubscription.widgetTimewindowChanged$.subscribe( () => { this.sources.forEach((source) => { if (this.displayPagination) { @@ -185,11 +185,10 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } ngOnDestroy(): void { - if (this.widgetTimewindowChangedSubscription) { - this.widgetTimewindowChangedSubscription.unsubscribe(); - this.widgetTimewindowChangedSubscription = null; + if (this.widgetTimewindowChanged$) { + this.widgetTimewindowChanged$.unsubscribe(); + this.widgetTimewindowChanged$ = null; } - this.ctx.defaultSubscription.widgetTimewindowChangedSubject.complete(); } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 3ce1779bf6..ffcaef06ef 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -67,7 +67,6 @@ export interface IDashboardComponent { autofillHeight: boolean; dashboardTimewindow: Timewindow; dashboardTimewindowChanged: Observable; - dashboardTimewindowChangedSubject: Subject; aliasController: IAliasController; stateController: IStateController; onUpdateTimewindow(startTimeMs: number, endTimeMs: number, interval?: number, persist?: boolean): void; From 838d6982a834225413c32efb79cafbc555040bd7 Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Mon, 11 Oct 2021 12:26:01 +0300 Subject: [PATCH 043/303] UI: make dashboard title translatable when 'Display dashboard title' option enabled --- .../components/dashboard-page/dashboard-page.component.html | 2 +- .../home/components/dashboard-page/dashboard-page.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index a6d91d87ae..8f97f5c7e8 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -148,7 +148,7 @@

-

{{ dashboard.title }}

+

{{ utils.customTranslation(dashboard.title, dashboard.title) }}

dashboard.title Date: Mon, 11 Oct 2021 12:53:47 +0300 Subject: [PATCH 044/303] fix swagger in telemetry controller after review --- .../controller/TelemetryController.java | 145 ++++++++++-------- 1 file changed, 79 insertions(+), 66 deletions(-) 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 8e3f5c16a7..051c19c0a4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -50,7 +50,6 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -110,6 +109,14 @@ import java.util.stream.Collectors; @Slf4j public class TelemetryController extends BaseController { + public static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; + public static final String ENTITY_SCOPE_DESCRIPTION = "A string value representing the entity scope. Required values: 'SERVER_SCOPE', 'CLIENT_SCOPE' or 'SHARED_SCOPE'. For example, 'SERVER_SCOPE'."; + public static final String ENTITY_ID_DESCRIPTION = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'"; + public static final String ENTITY_TIMESERIES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of timeseries keys. If keys are not selected, the result will return all the latest timeseries. For example, 'active,inactivityAlarmTime'"; + public static final String ENTITY_ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. If keys are not selected, the result will return all the latest timeseries. For example, 'active,inactivityAlarmTime'"; + public static final String ENTITY_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}'"; + public static final String DEVICE_ID_DESCRIPTION = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'"; + @Autowired private TimeseriesService tsService; @@ -135,101 +142,101 @@ public class TelemetryController extends BaseController { } } - @ApiOperation(value = "Get all existed attributes of entity by it`s type", - notes = "Returns key`s name of the attribute") + @ApiOperation(value = "Get all attributes for selected entity", + notes = "Returns key names for the selected entity id and type") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributeKeys( @ApiParam(value = "A string value representing the entity type. For example, 'ASSET'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the entity id of the required entity type. For example, '87b2fe90-2050-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr) throws ThingsboardException { + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); } - @ApiOperation(value = "Get all existed attributes of entity by type and scope") + @ApiOperation(value = "Get all attributes for selected entity by attributes scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributeKeysByScope( - @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the scope. For example, 'SERVER_SCOPE'. In the result will be return all server attributes") @PathVariable("scope") String scope) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_SCOPE_DESCRIPTION + " In the result will be return all server attributes") @PathVariable("scope") String scope) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); } - @ApiOperation(value = "Get all existed attributes of entity by it`s type", + @ApiOperation(value = "Get all attributes for selected entity id and type", notes = "Returns key and value of the attribute") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributes( - @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); } - @ApiOperation(value = "Get all existed attributes of entity by it`s type and scope") + @ApiOperation(value = "Get all attributes for selected entity id, type and scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes/{scope}", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributesByScope( - @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the entity type. For example, 'SERVER_SCOPE'") @PathVariable("scope") String scope, - @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); } - @ApiOperation(value = "Get all timeseries keys of entity", - notes = "Return all keys of timeseries of entity id and type") + @ApiOperation(value = "Get all timeseries keys for selected entity id and type") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/timeseries", method = RequestMethod.GET) @ResponseBody public DeferredResult getTimeseriesKeys( - @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); } - @ApiOperation(value = "Get all last timeseries of entity", - notes = "Return all last timeserie(last time updated or created) of entity id and type") + @ApiOperation(value = "Get all last timeseries for selected entity id and type", + notes = "Return all last timeserie(last time updated or created) for selected entity id and type") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET) @ResponseBody public DeferredResult getLatestTimeseries( - @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys", required = false) String keysStr, - @ApiParam(value = "A boolean value representing if value of timeseries is representing as a string (by default) or as original type") @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_TIMESERIES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr, + @ApiParam(value = "A boolean value to specify if values of specified timeseries keys will representing a string (by default) or use strict data type.") @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); } - @ApiOperation(value = "Get all last timeseries of entity", - notes = "Return all timeseries of entity in selected period of time. Based on this information can be built " + + @ApiOperation(value = "Get all timeseries for selected entity", + notes = "Return all timeseries for selected entity id, type and period of time. Based on this information can be built " + "widget on the dashboard to see updated telemetry in real-time") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"}) @ResponseBody public DeferredResult getTimeseries( - @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys") String keys, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_TIMESERIES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keys, @ApiParam(value = "A string value representing the start point of time") @RequestParam(name = "startTs") Long startTs, @ApiParam(value = "A string value representing the end point of time") @RequestParam(name = "endTs") Long endTs, @ApiParam(value = "A long value representing the period of time") @RequestParam(name = "interval", defaultValue = "0") Long interval, @RequestParam(name = "limit", defaultValue = "100") Integer limit, - @ApiParam(value = "A string value representing the function. For example, 'AVG'") @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, - @ApiParam(value = "A string value representing a sorting type") @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, + @ApiParam(value = "A string value representing the function. Available parameters: 'MIN', 'MAX', 'AVG', 'SUM', 'COUNT', 'NONE'." + + " If the interval is 0, aggStr will be converted to 'NONE' value. For example, 'AVG'") @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, + @ApiParam(value = "A string value representing a sorting type. Available values 'DESC' or 'ASC'") @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> { @@ -242,33 +249,33 @@ public class TelemetryController extends BaseController { }); } - @ApiOperation(value = "Create and save attribute of device") + @ApiOperation(value = "Create and save attribute for selected device") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveDeviceAttributes( - @ApiParam(value = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("deviceId") String deviceIdStr, - @ApiParam(value = "A string value representing the entity type. For example, 'SERVER_SCOPE'") @PathVariable("scope") String scope, - @ApiParam(value = "A string value representing the json object. Should contains key and value of the attribute. For example, '{\"key\":\"value\"}'") @RequestBody JsonNode request) throws ThingsboardException { + @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("deviceId") String deviceIdStr, + @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Create and save attribute of entity") + @ApiOperation(value = "Create and save attribute for selected entity") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityAttributesV1( - @ApiParam(value = "A string value representing the entity type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the entity id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the entity type. For example, 'SHARED_SCOPE'") @PathVariable("scope") String scope, - @ApiParam(value = "A string value representing the json object. Should contains key and value of the attribute. For example, '{\"key\":\"value\"}'") @RequestBody JsonNode request) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Create and save attribute of entity", - notes = "The same as saveEntityAttributesV1") + @ApiOperation(value = "Create and save attribute for selected entity", + notes = "The same as saveEntityAttributesV1") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/attributes/{scope}", method = RequestMethod.POST) @ResponseBody @@ -279,44 +286,44 @@ public class TelemetryController extends BaseController { return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Save telemetry of entity type and scope") + @ApiOperation(value = "Save telemetry for selected entity id, type and scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityTelemetry( - @ApiParam(value = "A string value representing the device type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the scope. For example, 'SERVER_SCOPE'") @PathVariable("scope") String scope, - @ApiParam(value = "A string value representing the json object. Should contains key and value of the attribute. For example, '{\"key\":\"value\"}'") @RequestBody String requestBody) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, 0L); } - @ApiOperation(value = "Save telemetry of entity type and scope", + @ApiOperation(value = "Save telemetry for selected entity id, type and scope", notes = "The TTL parameter is used to extract the number of days to store the data.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}/{ttl}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityTelemetryWithTTL( - @ApiParam(value = "A string value representing the device type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the scope. For example, 'SERVER_SCOPE'") @PathVariable("scope") String scope, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, @ApiParam(value = "A long value representing the amount of days.") @PathVariable("ttl") Long ttl, - @ApiParam(value = "A string value representing the json object. Should contains key and value of the attribute. For example, '{\"key\":\"value\"}'") @RequestBody String requestBody) throws ThingsboardException { + @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, ttl); } @ApiOperation(value = "Delete entity timeseries", - notes = "Delete all timeseries of entity in the required period of time") + notes = "Delete all timeseries for selected entity in the required period of time") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/delete", method = RequestMethod.DELETE) @ResponseBody public DeferredResult deleteEntityTimeseries( - @ApiParam(value = "A string value representing the device type. For example, 'DEVICE'") @PathVariable("entityType") String entityType, - @ApiParam(value = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'") @PathVariable("entityId") String entityIdStr, - @ApiParam(value = "A string value representing the entity keys. They are optional and listed with comma with no space between keys. For example, 'active,inactivityAlarmTime'") @RequestParam(name = "keys") String keysStr, - @ApiParam(value = "A boolean value representing if should be deleted all data of required key or only the latest") @RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_TIMESERIES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr, + @ApiParam(value = "A boolean value representing if should be deleted all data of required keys or only the latest") @RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys, @ApiParam(value = "A long value representing the start point of time") @RequestParam(name = "startTs", required = false) Long startTs, @ApiParam(value = "A long value representing the end point of time") @RequestParam(name = "endTs", required = false) Long endTs, @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { @@ -368,22 +375,28 @@ public class TelemetryController extends BaseController { }); } + @ApiOperation(value = "Delete entity attributes", + notes = "Delete entity attributes for selected device id and scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.DELETE) @ResponseBody - public DeferredResult deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr, - @PathVariable("scope") String scope, - @RequestParam(name = "keys") String keysStr) throws ThingsboardException { + public DeferredResult deleteEntityAttributes( + @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("deviceId") String deviceIdStr, + @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); return deleteAttributes(entityId, scope, keysStr); } + @ApiOperation(value = "Delete entity attributes", + notes = "Delete entity attributes for selected entity id and scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.DELETE) @ResponseBody - public DeferredResult deleteEntityAttributes(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @PathVariable("scope") String scope, - @RequestParam(name = "keys") String keysStr) throws ThingsboardException { + public DeferredResult deleteEntityAttributes( + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return deleteAttributes(entityId, scope, keysStr); } From 9534bf311e8796547f6e197171e4f920e0d49e76 Mon Sep 17 00:00:00 2001 From: Mariesnlk Date: Mon, 11 Oct 2021 16:28:11 +0300 Subject: [PATCH 045/303] fix swagger docs after riview --- .../server/controller/BaseController.java | 1 + .../server/controller/DeviceController.java | 2 +- .../controller/TelemetryController.java | 101 ++++++++++-------- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index f320b8eafa..8c0c63508d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -156,6 +156,7 @@ public abstract class BaseController { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; protected static final String HOME_DASHBOARD = "homeDashboardId"; + public static final String DEVICE_ID_DESCRIPTION = "A string value representing the device id."; private static final int DEFAULT_PAGE_SIZE = 1000; 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 2bb23ccae7..0cb1327f01 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -97,7 +97,7 @@ import static org.thingsboard.server.controller.EdgeController.EDGE_ID; @RequiredArgsConstructor @Slf4j public class DeviceController extends BaseController { - public static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String DEVICE_ID_PARAM_DESCRIPTION = BaseController.DEVICE_ID_DESCRIPTION + " For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; private final DeviceBulkImportService deviceBulkImportService; private static final String DEVICE_ID = "deviceId"; 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 051c19c0a4..f41ec2661a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -109,13 +109,17 @@ import java.util.stream.Collectors; @Slf4j public class TelemetryController extends BaseController { - public static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; - public static final String ENTITY_SCOPE_DESCRIPTION = "A string value representing the entity scope. Required values: 'SERVER_SCOPE', 'CLIENT_SCOPE' or 'SHARED_SCOPE'. For example, 'SERVER_SCOPE'."; + public static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type."; + public static final String DEVICE_ENTITY_TYPE_DESCRIPTION = ENTITY_TYPE_DESCRIPTION + " For example, 'DEVICE'"; + public static final String ASSET_ENTITY_TYPE_DESCRIPTION = ENTITY_TYPE_DESCRIPTION + " For example, 'ASSET'"; + public static final String ATTRIBUTES_SCOPE_DESCRIPTION = "A string value representing the attributes scope. Allowed values: 'SERVER_SCOPE', 'CLIENT_SCOPE' or 'SHARED_SCOPE'. "; + public static final String CLIENT_SCOPE_DESCRIPTION = ATTRIBUTES_SCOPE_DESCRIPTION + " For example, 'CLIENT_SCOPE'."; + public static final String SERVER_SCOPE_DESCRIPTION = ATTRIBUTES_SCOPE_DESCRIPTION + " For example, 'SERVER_SCOPE'."; public static final String ENTITY_ID_DESCRIPTION = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'"; - public static final String ENTITY_TIMESERIES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of timeseries keys. If keys are not selected, the result will return all the latest timeseries. For example, 'active,inactivityAlarmTime'"; - public static final String ENTITY_ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. If keys are not selected, the result will return all the latest timeseries. For example, 'active,inactivityAlarmTime'"; + public static final String ENTITY_TIMESERIES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of timeseries keys. If keys are not selected, the result will return all the latest timeseries. For example, 'temp,humidity'"; + public static final String ENTITY_ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. For example, 'active,inactivityAlarmTime'"; public static final String ENTITY_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}'"; - public static final String DEVICE_ID_DESCRIPTION = "A string value representing the device id. For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'"; + public static final String DEVICE_ID_DESCRIPTION = BaseController.DEVICE_ID_DESCRIPTION + "For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'"; @Autowired private TimeseriesService tsService; @@ -142,75 +146,78 @@ public class TelemetryController extends BaseController { } } - @ApiOperation(value = "Get all attributes for selected entity", - notes = "Returns key names for the selected entity id and type") + @ApiOperation(value = "Get all attribute keys for selected entity", + notes = "Returns key names for the selected entity") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributeKeys( - @ApiParam(value = "A string value representing the entity type. For example, 'ASSET'") @PathVariable("entityType") String entityType, + @ApiParam(value = ASSET_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); } - @ApiOperation(value = "Get all attributes for selected entity by attributes scope") + @ApiOperation(value = "Get all attributes for selected entity by attributes scope", + notes = "Returns key names for the selected entity by attributes scope ") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributeKeysByScope( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_SCOPE_DESCRIPTION + " In the result will be return all server attributes") @PathVariable("scope") String scope) throws ThingsboardException { + @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION + "For example, 'SERVER_SCOPE'. In the result will be return all server attributes") @PathVariable("scope") String scope) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); } - @ApiOperation(value = "Get all attributes for selected entity id and type", - notes = "Returns key and value of the attribute") + @ApiOperation(value = "Get all attributes for selected entity", + notes = "Returns keys and values of the attribute for selected entity") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributes( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); } - @ApiOperation(value = "Get all attributes for selected entity id, type and scope") + @ApiOperation(value = "Get all attributes for selected entity and attributes scope", + notes = "Returns keys and values of the attribute for selected entity and attributes scope") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes/{scope}", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributesByScope( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ASSET_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = SERVER_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); } - @ApiOperation(value = "Get all timeseries keys for selected entity id and type") + @ApiOperation(value = "Get all timeseries keys for selected entity", + notes = "Returns keys of the timeseries for selected entity") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/timeseries", method = RequestMethod.GET) @ResponseBody public DeferredResult getTimeseriesKeys( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ASSET_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); } - @ApiOperation(value = "Get all last timeseries for selected entity id and type", - notes = "Return all last timeserie(last time updated or created) for selected entity id and type") + @ApiOperation(value = "Get all last timeseries for selected entity", + notes = "Return all last timeserie(last time updated or created) for selected entity ") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET) @ResponseBody public DeferredResult getLatestTimeseries( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ASSET_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, @ApiParam(value = ENTITY_TIMESERIES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr, @ApiParam(value = "A boolean value to specify if values of specified timeseries keys will representing a string (by default) or use strict data type.") @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { @@ -221,20 +228,20 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Get all timeseries for selected entity", - notes = "Return all timeseries for selected entity id, type and period of time. Based on this information can be built " + + notes = "Return all timeseries for selected entity and period of time. Based on this information can be built " + "widget on the dashboard to see updated telemetry in real-time") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"}) @ResponseBody public DeferredResult getTimeseries( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, @ApiParam(value = ENTITY_TIMESERIES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keys, @ApiParam(value = "A string value representing the start point of time") @RequestParam(name = "startTs") Long startTs, @ApiParam(value = "A string value representing the end point of time") @RequestParam(name = "endTs") Long endTs, @ApiParam(value = "A long value representing the period of time") @RequestParam(name = "interval", defaultValue = "0") Long interval, @RequestParam(name = "limit", defaultValue = "100") Integer limit, - @ApiParam(value = "A string value representing the function. Available parameters: 'MIN', 'MAX', 'AVG', 'SUM', 'COUNT', 'NONE'." + + @ApiParam(value = "A string value representing the function. Allowed values: 'MIN', 'MAX', 'AVG', 'SUM', 'COUNT', 'NONE'." + " If the interval is 0, aggStr will be converted to 'NONE' value. For example, 'AVG'") @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, @ApiParam(value = "A string value representing a sorting type. Available values 'DESC' or 'ASC'") @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { @@ -249,32 +256,32 @@ public class TelemetryController extends BaseController { }); } - @ApiOperation(value = "Create and save attribute for selected device") + @ApiOperation(value = "Save and update attributes for selected device") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveDeviceAttributes( @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("deviceId") String deviceIdStr, - @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Create and save attribute for selected entity") + @ApiOperation(value = "Save and update attributes for selected entity") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityAttributesV1( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Create and save attribute for selected entity", + @ApiOperation(value = "Save and update attributes for selected entity", notes = "The same as saveEntityAttributesV1") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/attributes/{scope}", method = RequestMethod.POST) @@ -286,28 +293,28 @@ public class TelemetryController extends BaseController { return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Save telemetry for selected entity id, type and scope") + @ApiOperation(value = "Save and update telemetry for selected entity") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityTelemetry( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, 0L); } - @ApiOperation(value = "Save telemetry for selected entity id, type and scope", + @ApiOperation(value = "Save telemetry for selected entity with ttl", notes = "The TTL parameter is used to extract the number of days to store the data.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}/{ttl}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityTelemetryWithTTL( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, @ApiParam(value = "A long value representing the amount of days.") @PathVariable("ttl") Long ttl, @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); @@ -375,14 +382,14 @@ public class TelemetryController extends BaseController { }); } - @ApiOperation(value = "Delete entity attributes", - notes = "Delete entity attributes for selected device id and scope") + @ApiOperation(value = "Delete device attributes", + notes = "Delete device attributes for selected device") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.DELETE) @ResponseBody public DeferredResult deleteEntityAttributes( @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("deviceId") String deviceIdStr, - @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); return deleteAttributes(entityId, scope, keysStr); @@ -394,8 +401,8 @@ public class TelemetryController extends BaseController { @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.DELETE) @ResponseBody public DeferredResult deleteEntityAttributes( - @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, + @ApiParam(value = SERVER_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return deleteAttributes(entityId, scope, keysStr); From 2814c377acd45b3f8cb75955ede0fc5fb722261a Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Mon, 11 Oct 2021 16:29:46 +0300 Subject: [PATCH 046/303] Refactor rule chains importing --- .../controller/RuleChainController.java | 13 ++-- .../server/dao/rule/RuleChainService.java | 3 +- .../data/rule/RuleChainImportResult.java | 13 ++-- .../server/dao/rule/BaseRuleChainService.java | 59 +++++++++++-------- .../server/dao/rule/RuleChainDao.java | 5 ++ .../server/dao/sql/rule/JpaRuleChainDao.java | 7 +++ .../dao/sql/rule/RuleChainRepository.java | 8 ++- 7 files changed, 68 insertions(+), 40 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index a71fb70e0a..2fcd36f95b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -25,7 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -450,15 +449,17 @@ public class RuleChainController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST) @ResponseBody - public void importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { + public List importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); - List importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite); - if (!CollectionUtils.isEmpty(importResults)) { - for (RuleChainImportResult importResult : importResults) { - tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(), importResult.getLifecycleEvent()); + List importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite); + for (RuleChainImportResult importResult : importResults) { + if (importResult.getError() == null) { + tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(), + importResult.isUpdated() ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED); } } + return importResults; } catch (Exception e) { throw handleException(e); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index ae994d4122..e089d7bf47 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -23,7 +23,6 @@ import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainData; @@ -71,7 +70,7 @@ public interface RuleChainService { RuleChainData exportTenantRuleChains(TenantId tenantId, PageLink pageLink) throws ThingsboardException; - List importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, RuleChainType type, boolean overwrite); + List importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite); RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainImportResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainImportResult.java index 11a2f68a57..70c30de947 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainImportResult.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainImportResult.java @@ -15,17 +15,22 @@ */ package org.thingsboard.server.common.data.rule; -import lombok.AllArgsConstructor; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; @Data -@AllArgsConstructor public class RuleChainImportResult { + @JsonIgnore private TenantId tenantId; private RuleChainId ruleChainId; - private ComponentLifecycleEvent lifecycleEvent; + private String ruleChainName; + @JsonInclude(JsonInclude.Include.NON_DEFAULT) + private boolean updated; + @JsonInclude(JsonInclude.Include.NON_NULL) + private String error; + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 2ead3f4334..fa1c4ec173 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @@ -38,7 +39,6 @@ import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.NodeConnectionInfo; @@ -59,6 +59,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantDao; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -416,41 +417,46 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } @Override - public List importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, RuleChainType type, boolean overwrite) { + public List importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite) { List importResults = new ArrayList<>(); + setRandomRuleChainIds(ruleChainData); resetRuleNodeIds(ruleChainData.getMetadata()); resetRuleChainMetadataTenantIds(tenantId, ruleChainData.getMetadata()); - if (overwrite) { - List persistentRuleChains = findAllTenantRuleChains(tenantId, type); - for (RuleChain ruleChain : ruleChainData.getRuleChains()) { - ComponentLifecycleEvent lifecycleEvent; - Optional persistentRuleChainOpt = persistentRuleChains.stream().filter(rc -> rc.getName().equals(ruleChain.getName())).findFirst(); - if (persistentRuleChainOpt.isPresent()) { - setNewRuleChainId(ruleChain, ruleChainData.getMetadata(), ruleChain.getId(), persistentRuleChainOpt.get().getId()); - ruleChain.setRoot(persistentRuleChainOpt.get().isRoot()); - lifecycleEvent = ComponentLifecycleEvent.UPDATED; - } else { - ruleChain.setRoot(false); - lifecycleEvent = ComponentLifecycleEvent.CREATED; + + for (RuleChain ruleChain : ruleChainData.getRuleChains()) { + RuleChainImportResult importResult = new RuleChainImportResult(); + + ruleChain.setTenantId(tenantId); + ruleChain.setRoot(false); + + if (overwrite) { + Collection existingRuleChains = ruleChainDao.findByTenantIdAndTypeAndName(tenantId, + Optional.ofNullable(ruleChain.getType()).orElse(RuleChainType.CORE), ruleChain.getName()); + Optional existingRuleChain = existingRuleChains.stream().findFirst(); + if (existingRuleChain.isPresent()) { + setNewRuleChainId(ruleChain, ruleChainData.getMetadata(), ruleChain.getId(), existingRuleChain.get().getId()); + ruleChain.setRoot(existingRuleChain.get().isRoot()); + importResult.setUpdated(true); } - ruleChain.setTenantId(tenantId); - ruleChainDao.save(tenantId, ruleChain); - importResults.add(new RuleChainImportResult(tenantId, ruleChain.getId(), lifecycleEvent)); } - } else { - if (!CollectionUtils.isEmpty(ruleChainData.getRuleChains())) { - ruleChainData.getRuleChains().forEach(rc -> { - rc.setTenantId(tenantId); - rc.setRoot(false); - RuleChain savedRc = ruleChainDao.save(tenantId, rc); - importResults.add(new RuleChainImportResult(tenantId, savedRc.getId(), ComponentLifecycleEvent.CREATED)); - }); + + try { + ruleChain = saveRuleChain(ruleChain); + } catch (Exception e) { + importResult.setError(ExceptionUtils.getRootCauseMessage(e)); } + + importResult.setTenantId(tenantId); + importResult.setRuleChainId(ruleChain.getId()); + importResult.setRuleChainName(ruleChain.getName()); + importResults.add(importResult); } - if (!CollectionUtils.isEmpty(ruleChainData.getMetadata())) { + + if (CollectionUtils.isNotEmpty(ruleChainData.getMetadata())) { ruleChainData.getMetadata().forEach(md -> saveRuleChainMetaData(tenantId, md)); } + return importResults; } @@ -723,4 +729,5 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC checkRuleNodesAndDelete(tenantId, entity.getId()); } }; + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index 98ad0b34a7..03fd25e944 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.rule; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleChain; @@ -22,6 +23,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.TenantEntityDao; +import java.util.Collection; import java.util.UUID; /** @@ -74,4 +76,7 @@ public interface RuleChainDao extends Dao, TenantEntityDao { * @return the list of rule chain objects */ PageData findAutoAssignToEdgeRuleChainsByTenantId(UUID tenantId, PageLink pageLink); + + Collection findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 040e60daad..483ab39f06 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.model.sql.RuleChainEntity; import org.thingsboard.server.dao.rule.RuleChainDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import java.util.Collection; import java.util.Objects; import java.util.UUID; @@ -97,8 +98,14 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name) { + return DaoUtil.convertDataList(ruleChainRepository.findByTenantIdAndTypeAndName(tenantId.getId(), type, name)); + } + @Override public Long countByTenantId(TenantId tenantId) { return ruleChainRepository.countByTenantId(tenantId.getId()); } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java index 86a147cc57..fda0a0d7f0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java @@ -23,6 +23,7 @@ import org.springframework.data.repository.query.Param; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.model.sql.RuleChainEntity; +import java.util.List; import java.util.UUID; public interface RuleChainRepository extends PagingAndSortingRepository { @@ -55,10 +56,13 @@ public interface RuleChainRepository extends PagingAndSortingRepository findAutoAssignByTenantId(@Param("tenantId") UUID tenantId, - @Param("searchText") String searchText, - Pageable pageable); + @Param("searchText") String searchText, + Pageable pageable); RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType); Long countByTenantId(UUID tenantId); + + List findByTenantIdAndTypeAndName(UUID tenantId, RuleChainType type, String name); + } From e884724e74312636565e72c760b16c8176d3c0ef Mon Sep 17 00:00:00 2001 From: Matt Magoffin Date: Tue, 12 Oct 2021 09:14:09 +1300 Subject: [PATCH 047/303] Revert to e1021f3024 per PR request. --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 26cafb63aa..3343ee8cac 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 @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
"}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,z=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var Q,_=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Q||(Q={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=_,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(Q),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=z,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(z.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(z.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),Qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[Qe,_e,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[Qe,_e,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,ze,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=ze,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=Qe,e.ɵci=_e,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
"}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,z=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var Q,_=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Q||(Q={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=_,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(Q),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=z,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(z.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(z.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),Qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[Qe,_e,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[Qe,_e,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,ze,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=ze,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=Qe,e.ɵci=_e,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 8e0b76fb7a292001867037956966ce4075dc5a2c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 12 Oct 2021 11:46:23 +0300 Subject: [PATCH 048/303] Added Swagger API documentation for Edge Controller --- .../server/controller/EdgeController.java | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 21c39cdd58..bed585c711 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.ListenableFuture; +import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -75,6 +76,8 @@ public class EdgeController extends BaseController { private final EdgeBulkImportService edgeBulkImportService; public static final String EDGE_ID = "edgeId"; + public static final String EDGE_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the edge is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the edge is assigned to the same customer."; @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges/enabled", method = RequestMethod.GET) @@ -83,6 +86,8 @@ public class EdgeController extends BaseController { return edgesEnabled; } + @ApiOperation(value = "Get Edge (getEdgeById)", + notes = "Get the Edge object based on the provided Edge Id. " + EDGE_SECURITY_CHECK) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET) @ResponseBody @@ -100,6 +105,8 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Edge Info (getEdgeInfoById)", + notes = "Get the Edge Info object based on the provided Edge Id. " + EDGE_SECURITY_CHECK) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/info/{edgeId}", method = RequestMethod.GET) @ResponseBody @@ -117,6 +124,10 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Create Or Update Edge (saveEdge)", + notes = "Creates or Updates the Edge. Platform generates random Edge Id during edge creation. " + + "The edge id will be present in the response. " + + "Specify the Edge id when you would like to update the edge. Referencing non-existing edge Id will cause an error.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge", method = RequestMethod.POST) @ResponseBody @@ -163,6 +174,8 @@ public class EdgeController extends BaseController { logEntityAction(edge.getId(), edge, null, updated ? ActionType.UPDATED : ActionType.ADDED, null); } + @ApiOperation(value = "Delete edge (deleteEdge)", + notes = "Deletes the edge. Referencing non-existing edge Id will cause an error.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -191,6 +204,9 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Tenant Edges (getEdges)", + notes = "Returns a page of edges owned by tenant. " + + PAGE_DATA_PARAMETERS) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -208,6 +224,8 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Assign edge to customer (assignEdgeToCustomer)", + notes = "Creates assignment of the edge to customer. Customer will be able to query edge afterwards.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST) @ResponseBody @@ -243,6 +261,8 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Unassign edge from customer (unassignEdgeFromCustomer)", + notes = "Clears assignment of the edge to customer. Customer will not be able to query edge afterwards.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE) @ResponseBody @@ -277,6 +297,10 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Make edge publicly available (assignEdgeToPublicCustomer)", + notes = "Edge will be available for non-authorized (not logged-in) users. " + + "This is useful to create dashboards that you plan to share/embed on a publicly available website. " + + "However, users that are logged-in and belong to different tenant will not be able to access the edge.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST) @ResponseBody @@ -304,6 +328,9 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Tenant Edges (getTenantEdges)", + notes = "Returns a page of edges owned by tenant. " + + PAGE_DATA_PARAMETERS) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -327,6 +354,9 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Tenant Edge Infos (getTenantEdgeInfos)", + notes = "Returns a page of edges info objects owned by tenant. " + + PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -350,6 +380,9 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Tenant Edge (getTenantEdge)", + notes = "Requested edge must be owned by tenant or customer that the user belongs to. " + + "Edge name is an unique property of edge. So it can be used to identify the edge.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET) @ResponseBody @@ -362,6 +395,9 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Set root rule chain for provided edge (setRootRuleChain)", + notes = "Change root rule chain of the edge from the current to the new provided rule chain. \n" + + "This operation will send an notification to remote edge service to update root rule chain remotely.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST) @ResponseBody @@ -394,6 +430,9 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Customer Edges (getCustomerEdges)", + notes = "Returns a page of edges objects assigned to customer. " + + PAGE_DATA_PARAMETERS) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -429,6 +468,9 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Customer Edge Infos (getCustomerEdgeInfos)", + notes = "Returns a page of edges info objects assigned to customer. " + + PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -464,6 +506,8 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Edges By Ids (getEdgesByIds)", + notes = "Requested edges must be owned by tenant or assigned to customer which user is performing the request. ") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) @ResponseBody @@ -496,6 +540,10 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Find related edges (findByQuery)", + notes = "Returns all edges that are related to the specific entity. " + + "The entity id, relation type, device types, depth of the search, and other query parameters defined using complex 'EdgeSearchQuery' object. " + + "See 'Model' tab of the Parameters for more info.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges", method = RequestMethod.POST) @ResponseBody @@ -527,6 +575,8 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Get Edge Types (getEdgeTypes)", + notes = "Returns a set of unique edge types based on edges that are either owned by the tenant or assigned to the customer which user is performing the request.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/types", method = RequestMethod.GET) @ResponseBody @@ -541,6 +591,8 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Sync edge (syncEdge)", + notes = "Starts synchronization process between edge and cloud - all entities that are assigned to particular edge are going to be send to remote edge service.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/sync/{edgeId}", method = RequestMethod.POST) public void syncEdge(@PathVariable("edgeId") String strEdgeId) throws ThingsboardException { @@ -560,6 +612,8 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Find missing rule chains (findMissingToRelatedRuleChains)", + notes = "Returns list of rule chains IDs that are not assigned to particular edge, but these rule chains are present in the already assigned rule chains to edge") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/missingToRelatedRuleChains/{edgeId}", method = RequestMethod.GET) @ResponseBody @@ -575,9 +629,11 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Import the bulk of edges (processEdgesBulkImport)", + notes = "There's an ability to import the bulk of edges using the only .csv file.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PostMapping("/edge/bulk_import") - public BulkImportResult processEdgeBulkImport(@RequestBody BulkImportRequest request) throws Exception { + public BulkImportResult processEdgesBulkImport(@RequestBody BulkImportRequest request) throws Exception { SecurityUser user = getCurrentUser(); RuleChain edgeTemplateRootRuleChain = ruleChainService.getEdgeTemplateRootRuleChain(user.getTenantId()); if (edgeTemplateRootRuleChain == null) { From c68cbff33549c182794c555a4e0c0ffce4145ce2 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 12 Oct 2021 11:52:24 +0300 Subject: [PATCH 049/303] Added more API swagger docs for edge controller --- .../thingsboard/server/controller/EdgeController.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index bed585c711..0de087f238 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -79,6 +79,8 @@ public class EdgeController extends BaseController { public static final String EDGE_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the edge is owned by the same tenant. " + "If the user has the authority of 'Customer User', the server checks that the edge is assigned to the same customer."; + @ApiOperation(value = "Is edges support enabled (isEdgesSupportEnabled)", + notes = "Returns 'true' if edges support enabled on server, 'false' - otherwise.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges/enabled", method = RequestMethod.GET) @ResponseBody @@ -397,7 +399,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Set root rule chain for provided edge (setRootRuleChain)", notes = "Change root rule chain of the edge from the current to the new provided rule chain. \n" + - "This operation will send an notification to remote edge service to update root rule chain remotely.") + "This operation will send a notification to remote edge service to update root rule chain remotely.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST) @ResponseBody @@ -592,7 +594,8 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Sync edge (syncEdge)", - notes = "Starts synchronization process between edge and cloud - all entities that are assigned to particular edge are going to be send to remote edge service.") + notes = "Starts synchronization process between edge and cloud. \n" + + "All entities that are assigned to particular edge are going to be send to remote edge service.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/sync/{edgeId}", method = RequestMethod.POST) public void syncEdge(@PathVariable("edgeId") String strEdgeId) throws ThingsboardException { @@ -613,7 +616,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Find missing rule chains (findMissingToRelatedRuleChains)", - notes = "Returns list of rule chains IDs that are not assigned to particular edge, but these rule chains are present in the already assigned rule chains to edge") + notes = "Returns list of rule chains ids that are not assigned to particular edge, but these rule chains are present in the already assigned rule chains to edge") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/missingToRelatedRuleChains/{edgeId}", method = RequestMethod.GET) @ResponseBody From 427e7ac0944b0247b21f8f2cfb3214fe463907af Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 12 Oct 2021 12:58:25 +0300 Subject: [PATCH 050/303] Added swagger API for edge event controller. Added search text usage for edge event type. Code cleanup --- .../server/controller/BaseController.java | 2 +- .../server/controller/EdgeEventController.java | 13 +++++++++++++ .../server/dao/model/sql/EdgeEventEntity.java | 4 +--- .../server/dao/sql/edge/EdgeEventRepository.java | 8 ++++++-- .../server/dao/sql/edge/JpaBaseEdgeEventDao.java | 3 +++ 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index ad54aaf526..f04a6f177c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -174,7 +174,7 @@ public abstract class BaseController { protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; - + protected final String EDGE_EVENT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge event type name."; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java index 22191efddf..038df906fa 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -45,17 +47,28 @@ public class EdgeEventController extends BaseController { public static final String EDGE_ID = "edgeId"; + @ApiOperation(value = "Get Edge Events (getEdgeEvents)", + notes = "Returns a page of edge events for the requested edge. " + + PAGE_DATA_PARAMETERS) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/events", method = RequestMethod.GET) @ResponseBody public PageData getEdgeEvents( + @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) @PathVariable(EDGE_ID) String strEdgeId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = EDGE_EVENT_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = "Timestamp. Edge events with creation time before it won't be queried") @RequestParam(required = false) Long startTime, + @ApiParam(value = "Timestamp. Edge events with creation time after it won't be queried") @RequestParam(required = false) Long endTime) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java index 2aad852c89..b30d40470b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.model.sql; -import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.databind.JsonNode; import lombok.Data; import lombok.EqualsAndHashCode; @@ -40,15 +39,14 @@ import javax.persistence.Table; import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ACTION_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_BODY_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_COLUMN_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_EDGE_ID_PROPERTY; -import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_BODY_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ENTITY_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TENANT_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_UID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EPOCH_DIFF; -import static org.thingsboard.server.dao.model.ModelConstants.EVENT_UID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN; @Data diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java index 4962b2e8d2..24b4084e1f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java @@ -31,10 +31,12 @@ public interface EdgeEventRepository extends PagingAndSortingRepository= :startTime) " + - "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + + "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT(:textSearch, '%'))" ) Page findEdgeEventsByTenantIdAndEdgeId(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, + @Param("textSearch") String textSearch, @Param("startTime") Long startTime, @Param("endTime") Long endTime, Pageable pageable); @@ -44,10 +46,12 @@ public interface EdgeEventRepository extends PagingAndSortingRepository= :startTime) " + "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + - "AND e.edgeEventAction <> 'TIMESERIES_UPDATED'" + "AND e.edgeEventAction <> 'TIMESERIES_UPDATED' " + + "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT(:textSearch, '%'))" ) Page findEdgeEventsByTenantIdAndEdgeIdWithoutTimeseriesUpdated(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, + @Param("textSearch") String textSearch, @Param("startTime") Long startTime, @Param("endTime") Long endTime, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index 050d0181f0..7a5eb50def 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -39,6 +39,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -107,6 +108,7 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao Date: Tue, 12 Oct 2021 13:11:24 +0300 Subject: [PATCH 051/303] fix swagger in telemetry controller --- .../server/controller/BaseController.java | 4 +- .../controller/TelemetryController.java | 191 ++++++++++-------- 2 files changed, 104 insertions(+), 91 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 833de053fe..fbd1ba6ecf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -174,12 +174,12 @@ public abstract class BaseController { protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; - + protected static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; + protected static final String ENTITY_ID_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; protected static final String HOME_DASHBOARD = "homeDashboardId"; - public static final String DEVICE_ID_DESCRIPTION = "A string value representing the device id."; private static final int DEFAULT_PAGE_SIZE = 1000; 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 f41ec2661a..60e61a64a1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -109,17 +109,16 @@ import java.util.stream.Collectors; @Slf4j public class TelemetryController extends BaseController { - public static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type."; - public static final String DEVICE_ENTITY_TYPE_DESCRIPTION = ENTITY_TYPE_DESCRIPTION + " For example, 'DEVICE'"; - public static final String ASSET_ENTITY_TYPE_DESCRIPTION = ENTITY_TYPE_DESCRIPTION + " For example, 'ASSET'"; - public static final String ATTRIBUTES_SCOPE_DESCRIPTION = "A string value representing the attributes scope. Allowed values: 'SERVER_SCOPE', 'CLIENT_SCOPE' or 'SHARED_SCOPE'. "; - public static final String CLIENT_SCOPE_DESCRIPTION = ATTRIBUTES_SCOPE_DESCRIPTION + " For example, 'CLIENT_SCOPE'."; - public static final String SERVER_SCOPE_DESCRIPTION = ATTRIBUTES_SCOPE_DESCRIPTION + " For example, 'SERVER_SCOPE'."; - public static final String ENTITY_ID_DESCRIPTION = "A string value representing the entity id. For example, '16cdaaf0-229d-11ec-b9f0-231c4d2593da'"; - public static final String ENTITY_TIMESERIES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of timeseries keys. If keys are not selected, the result will return all the latest timeseries. For example, 'temp,humidity'"; - public static final String ENTITY_ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. For example, 'active,inactivityAlarmTime'"; - public static final String ENTITY_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}'"; - public static final String DEVICE_ID_DESCRIPTION = BaseController.DEVICE_ID_DESCRIPTION + "For example, 'e0034860-2065-11ec-8a0a-15ac1b4580c2'"; + private static final String ATTRIBUTES_SCOPE_DESCRIPTION = "A string value representing the attributes scope. For example, 'SERVER_SCOPE'."; + private static final String ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. For example, 'active,inactivityAlarmTime'."; + private static final String ATTRIBUTES_SCOPE_ALLOWED_VALUES = "SERVER_SCOPE, CLIENT_SCOPE, SHARED_SCOPE"; + private static final String ATTRIBUTES_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}'"; + + private static final String TELEMETRY_KEYS_DESCRIPTION = "A string value representing the comma-separated list of timeseries keys. If keys are not selected, the result will return all latest timeseries. For example, 'temp,humidity'."; + private static final String TELEMETRY_SCOPE_DESCRIPTION = "Value is not used in the API call implementation"; + private static final String TELEMETRY_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}' or '{\"ts\":1527863043000,\"values\":{\"key1\":\"value1\",\"key2\":\"value2\"}}'"; + + private static final String STRICT_DATA_TYPES_DESCRIPTION = "A boolean value to specify if values of selected timeseries keys will representing a string (by default) or use strict data type."; @Autowired private TimeseriesService tsService; @@ -146,104 +145,112 @@ public class TelemetryController extends BaseController { } } - @ApiOperation(value = "Get all attribute keys for selected entity", - notes = "Returns key names for the selected entity") + @ApiOperation(value = "Get all attribute keys (getAttributeKeys)", + notes = "Returns key names for the selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributeKeys( - @ApiParam(value = ASSET_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); } - @ApiOperation(value = "Get all attributes for selected entity by attributes scope", - notes = "Returns key names for the selected entity by attributes scope ") + @ApiOperation(value = "Get all attributes by scope (getAttributeKeysByScope)", + notes = "Returns key names of specified scope for the selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributeKeysByScope( - @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION + "For example, 'SERVER_SCOPE'. In the result will be return all server attributes") @PathVariable("scope") String scope) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); } - @ApiOperation(value = "Get all attributes for selected entity", - notes = "Returns keys and values of the attribute for selected entity") + @ApiOperation(value = "Get attributes (getAttributes)", + notes = "Returns JSON array of AttributeData objects for the selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributes( - @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); } - @ApiOperation(value = "Get all attributes for selected entity and attributes scope", - notes = "Returns keys and values of the attribute for selected entity and attributes scope") + @ApiOperation(value = "Get attributes by scope (getAttributesByScope)", + notes = "Returns JSON array of AttributeData objects for the selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes/{scope}", method = RequestMethod.GET) @ResponseBody public DeferredResult getAttributesByScope( - @ApiParam(value = ASSET_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = SERVER_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, - @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { + @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, + @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); } - @ApiOperation(value = "Get all timeseries keys for selected entity", - notes = "Returns keys of the timeseries for selected entity") + @ApiOperation(value = "Get timeseries keys (getTimeseriesKeys)", + notes = "Returns latest timeseries keys for selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/timeseries", method = RequestMethod.GET) @ResponseBody public DeferredResult getTimeseriesKeys( - @ApiParam(value = ASSET_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); } - @ApiOperation(value = "Get all last timeseries for selected entity", - notes = "Return all last timeserie(last time updated or created) for selected entity ") + @ApiOperation(value = "Get latest timeseries (getLatestTimeseries)", + notes = "Returns JSON object with mapping latest timeseries keys to JSON arrays of TsData objects for the selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET) @ResponseBody public DeferredResult getLatestTimeseries( - @ApiParam(value = ASSET_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_TIMESERIES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr, - @ApiParam(value = "A boolean value to specify if values of specified timeseries keys will representing a string (by default) or use strict data type.") @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { + @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr, + @ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION) + @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); } - @ApiOperation(value = "Get all timeseries for selected entity", - notes = "Return all timeseries for selected entity and period of time. Based on this information can be built " + - "widget on the dashboard to see updated telemetry in real-time") + @ApiOperation(value = "Get timeseries (getTimeseries)", + notes = "Returns JSON object with mapping timeseries keys to JSON arrays of TsData objects based on specified filters for the selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"}) @ResponseBody public DeferredResult getTimeseries( - @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_TIMESERIES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keys, - @ApiParam(value = "A string value representing the start point of time") @RequestParam(name = "startTs") Long startTs, - @ApiParam(value = "A string value representing the end point of time") @RequestParam(name = "endTs") Long endTs, - @ApiParam(value = "A long value representing the period of time") @RequestParam(name = "interval", defaultValue = "0") Long interval, + @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keys, + @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") + @RequestParam(name = "startTs") Long startTs, + @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") + @RequestParam(name = "endTs") Long endTs, + @ApiParam(value = "A long value representing the aggregation interval(milliseconds) range.") + @RequestParam(name = "interval", defaultValue = "0") Long interval, + @ApiParam(value = "An integer value representing max number of selected data points.", defaultValue = "100") @RequestParam(name = "limit", defaultValue = "100") Integer limit, - @ApiParam(value = "A string value representing the function. Allowed values: 'MIN', 'MAX', 'AVG', 'SUM', 'COUNT', 'NONE'." + - " If the interval is 0, aggStr will be converted to 'NONE' value. For example, 'AVG'") @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, - @ApiParam(value = "A string value representing a sorting type. Available values 'DESC' or 'ASC'") @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, + @ApiParam(value = "A string value representing the aggregation function. " + + "If the interval is not specified, 'agg' parameter will be converted to 'NONE' value.", + allowableValues = "MIN, MAX, AVG, SUM, COUNT, NONE") + @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, + @ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION) @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> { @@ -256,83 +263,88 @@ public class TelemetryController extends BaseController { }); } - @ApiOperation(value = "Save and update attributes for selected device") + @ApiOperation(value = "Save or update device attributes (saveDeviceAttributes)") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveDeviceAttributes( - @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("deviceId") String deviceIdStr, - @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, - @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { + @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) @PathVariable("deviceId") String deviceIdStr, + @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, + @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Save and update attributes for selected entity") + @ApiOperation(value = "Save or update attributes (saveEntityAttributesV1)") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityAttributesV1( - @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, - @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, + @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Save and update attributes for selected entity", - notes = "The same as saveEntityAttributesV1") + @ApiOperation(value = "Save or update attributes (saveEntityAttributesV2)") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/attributes/{scope}", method = RequestMethod.POST) @ResponseBody - public DeferredResult saveEntityAttributesV2(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @PathVariable("scope") String scope, - @RequestBody JsonNode request) throws ThingsboardException { + public DeferredResult saveEntityAttributesV2( + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, + @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION) @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Save and update telemetry for selected entity") + @ApiOperation(value = "Save or update telemetry (saveEntityTelemetry)") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityTelemetry( - @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, - @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, 0L); } - @ApiOperation(value = "Save telemetry for selected entity with ttl", + @ApiOperation(value = "Save or update telemetry with TTL (saveEntityTelemetryWithTTL)", notes = "The TTL parameter is used to extract the number of days to store the data.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}/{ttl}", method = RequestMethod.POST) @ResponseBody public DeferredResult saveEntityTelemetryWithTTL( - @ApiParam(value = DEVICE_ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, - @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, - @ApiParam(value = "A long value representing the amount of days.") @PathVariable("ttl") Long ttl, - @ApiParam(value = ENTITY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, + @ApiParam(value = "A long value representing TTL(Time to Live) parameter.") @PathVariable("ttl") Long ttl, + @ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, ttl); } - @ApiOperation(value = "Delete entity timeseries", - notes = "Delete all timeseries for selected entity in the required period of time") + @ApiOperation(value = "Delete entity timeseries (deleteEntityTimeseries)", + notes = "Delete timeseries in the specified time range for selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/delete", method = RequestMethod.DELETE) @ResponseBody public DeferredResult deleteEntityTimeseries( @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = ENTITY_TIMESERIES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr, - @ApiParam(value = "A boolean value representing if should be deleted all data of required keys or only the latest") @RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys, - @ApiParam(value = "A long value representing the start point of time") @RequestParam(name = "startTs", required = false) Long startTs, - @ApiParam(value = "A long value representing the end point of time") @RequestParam(name = "endTs", required = false) Long endTs, + @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr, + @ApiParam(value = "A boolean value to specify if should be deleted all data for selected keys or only data that are in the selected time range.") + @RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys, + @ApiParam(value = "A long value representing the start timestamp(milliseconds) of removal time range.") + @RequestParam(name = "startTs", required = false) Long startTs, + @ApiParam(value = "A long value representing the end timestamp(milliseconds) of removal time range.") + @RequestParam(name = "endTs", required = false) Long endTs, + @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten if the current latest value was removed, otherwise, the new latest value will not set.") @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); @@ -382,28 +394,29 @@ public class TelemetryController extends BaseController { }); } - @ApiOperation(value = "Delete device attributes", - notes = "Delete device attributes for selected device") + @ApiOperation(value = "Delete device attributes (deleteEntityAttributes)", + notes = "Delete attributes of specified scope for selected device.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.DELETE) @ResponseBody public DeferredResult deleteEntityAttributes( - @ApiParam(value = DEVICE_ID_DESCRIPTION) @PathVariable("deviceId") String deviceIdStr, - @ApiParam(value = CLIENT_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, - @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { + @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) @PathVariable("deviceId") String deviceIdStr, + @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, + @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); return deleteAttributes(entityId, scope, keysStr); } - @ApiOperation(value = "Delete entity attributes", - notes = "Delete entity attributes for selected entity id and scope") + @ApiOperation(value = "Delete entity attributes (deleteEntityAttributes)", + notes = "Delete attributes of specified scope for selected entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.DELETE) @ResponseBody public DeferredResult deleteEntityAttributes( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, - @ApiParam(value = SERVER_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, - @ApiParam(value = ENTITY_ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String entityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String entityIdStr, + @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, + @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return deleteAttributes(entityId, scope, keysStr); } From 1c5ca328e9859b580d8bc1c670e1f1938f81a0dc Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 12 Oct 2021 13:12:27 +0300 Subject: [PATCH 052/303] Added ApiParam to edge controller methods --- .../server/controller/BaseController.java | 4 +- .../server/controller/EdgeController.java | 70 +++++++++++++++---- .../controller/EdgeEventController.java | 2 +- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index f04a6f177c..edec95a6a8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -162,6 +162,7 @@ public abstract class BaseController { public static final String TENANT_ID_PARAM_DESCRIPTION = "A string value representing the tenant id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String EDGE_ID_PARAM_DESCRIPTION = "A string value representing the edge id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -174,7 +175,8 @@ public abstract class BaseController { protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; - protected final String EDGE_EVENT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge event type name."; + protected final String EDGE_TYPE_DESCRIPTION = "A string value representing the edge type. For example, 'default'"; + protected final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name."; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 0de087f238..da8efc5bde 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -18,6 +18,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.ListenableFuture; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -93,7 +94,8 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET) @ResponseBody - public Edge getEdgeById(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { + public Edge getEdgeById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); @@ -112,7 +114,8 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/info/{edgeId}", method = RequestMethod.GET) @ResponseBody - public EdgeInfo getEdgeInfoById(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { + public EdgeInfo getEdgeInfoById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); @@ -133,7 +136,8 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge", method = RequestMethod.POST) @ResponseBody - public Edge saveEdge(@RequestBody Edge edge) throws ThingsboardException { + public Edge saveEdge(@ApiParam(value = "A JSON value representing the ed.") + @RequestBody Edge edge) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); edge.setTenantId(tenantId); @@ -181,7 +185,8 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteEdge(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { + public void deleteEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); @@ -212,10 +217,15 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public PageData getEdges(@RequestParam int pageSize, + public PageData getEdges(@ApiParam(value = PAGE_SIZE_DESCRIPTION) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); @@ -231,7 +241,9 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST) @ResponseBody - public Edge assignEdgeToCustomer(@PathVariable("customerId") String strCustomerId, + public Edge assignEdgeToCustomer(@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION) + @PathVariable("customerId") String strCustomerId, + @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter("customerId", strCustomerId); checkParameter(EDGE_ID, strEdgeId); @@ -268,7 +280,8 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE) @ResponseBody - public Edge unassignEdgeFromCustomer(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { + public Edge unassignEdgeFromCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); @@ -306,7 +319,8 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST) @ResponseBody - public Edge assignEdgeToPublicCustomer(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { + public Edge assignEdgeToPublicCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); @@ -337,11 +351,17 @@ public class EdgeController extends BaseController { @RequestMapping(value = "/tenant/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getTenantEdges( + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = EDGE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, + @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); @@ -363,11 +383,17 @@ public class EdgeController extends BaseController { @RequestMapping(value = "/tenant/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getTenantEdgeInfos( + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = EDGE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, + @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); @@ -388,7 +414,8 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET) @ResponseBody - public Edge getTenantEdge(@RequestParam String edgeName) throws ThingsboardException { + public Edge getTenantEdge(@ApiParam(value = "Unique name of the edge") + @RequestParam String edgeName) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName)); @@ -403,7 +430,9 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST) @ResponseBody - public Edge setRootRuleChain(@PathVariable(EDGE_ID) String strEdgeId, + public Edge setRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @PathVariable(EDGE_ID) String strEdgeId, + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) @PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); checkParameter("ruleChainId", strRuleChainId); @@ -439,12 +468,19 @@ public class EdgeController extends BaseController { @RequestMapping(value = "/customer/{customerId}/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getCustomerEdges( + @ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION) @PathVariable("customerId") String strCustomerId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = EDGE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, + @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("customerId", strCustomerId); try { @@ -477,12 +513,19 @@ public class EdgeController extends BaseController { @RequestMapping(value = "/customer/{customerId}/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getCustomerEdgeInfos( + @ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION) @PathVariable("customerId") String strCustomerId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = EDGE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, + @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("customerId", strCustomerId); try { @@ -514,6 +557,7 @@ public class EdgeController extends BaseController { @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) @ResponseBody public List getEdgesByIds( + @ApiParam(value = "A list of edges ids, separated by comma ','") @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException { checkArrayParameter("edgeIds", strEdgeIds); try { @@ -598,7 +642,8 @@ public class EdgeController extends BaseController { "All entities that are assigned to particular edge are going to be send to remote edge service.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/sync/{edgeId}", method = RequestMethod.POST) - public void syncEdge(@PathVariable("edgeId") String strEdgeId) throws ThingsboardException { + public void syncEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @PathVariable("edgeId") String strEdgeId) throws ThingsboardException { checkParameter("edgeId", strEdgeId); try { if (isEdgesEnabled()) { @@ -620,7 +665,8 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/missingToRelatedRuleChains/{edgeId}", method = RequestMethod.GET) @ResponseBody - public String findMissingToRelatedRuleChains(@PathVariable("edgeId") String strEdgeId) throws ThingsboardException { + public String findMissingToRelatedRuleChains(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @PathVariable("edgeId") String strEdgeId) throws ThingsboardException { try { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); edgeId = checkNotNull(edgeId); diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java index 038df906fa..13fafd4eed 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java @@ -60,7 +60,7 @@ public class EdgeEventController extends BaseController { @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, - @ApiParam(value = EDGE_EVENT_TEXT_SEARCH_DESCRIPTION) + @ApiParam(value = "The case insensitive 'startsWith' filter based on the edge event type name.") @RequestParam(required = false) String textSearch, @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, From 305409a0dc4c46593ae6478d815b5b2d10e21356 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 12 Oct 2021 14:24:50 +0300 Subject: [PATCH 053/303] JpaBaseEdgeEventDao: sql query timeout 1 hour --- .../thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index 050d0181f0..c9795782ec 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -43,6 +43,7 @@ import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -145,6 +146,7 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao Date: Tue, 12 Oct 2021 14:25:24 +0300 Subject: [PATCH 054/303] PsqlEventCleanupRepository.java: sql query timeout 1 hour --- .../server/dao/sql/event/PsqlEventCleanupRepository.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/PsqlEventCleanupRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/PsqlEventCleanupRepository.java index b19c8b0712..7577e0730a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/PsqlEventCleanupRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/PsqlEventCleanupRepository.java @@ -24,6 +24,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.concurrent.TimeUnit; @Slf4j @PsqlDao @@ -37,6 +38,7 @@ public class PsqlEventCleanupRepository extends JpaAbstractDaoListeningExecutorS stmt.setLong(1, otherEventsTtl); stmt.setLong(2, debugEventsTtl); stmt.setLong(3, 0); + stmt.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(1)); stmt.execute(); printWarnings(stmt); try (ResultSet resultSet = stmt.getResultSet()){ From 2dc1f18a2d396068850a0c36d2a18571e4eea62b Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 12 Oct 2021 14:27:02 +0300 Subject: [PATCH 055/303] HsqlEventCleanupRepository: sql query timeout 1 hour --- .../server/dao/sql/event/HsqlEventCleanupRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/HsqlEventCleanupRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/HsqlEventCleanupRepository.java index 7ea832ee32..38299e9443 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/HsqlEventCleanupRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/HsqlEventCleanupRepository.java @@ -23,6 +23,7 @@ import org.thingsboard.server.dao.util.HsqlDao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.concurrent.TimeUnit; @Slf4j @HsqlDao @@ -35,6 +36,7 @@ public class HsqlEventCleanupRepository extends JpaAbstractDaoListeningExecutorS try (Connection connection = dataSource.getConnection(); PreparedStatement stmt = connection.prepareStatement("DELETE FROM event WHERE ts < ? AND event_type != 'DEBUG_RULE_NODE' AND event_type != 'DEBUG_RULE_CHAIN'")) { stmt.setLong(1, otherExpirationTime); + stmt.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(1)); stmt.execute(); } catch (SQLException e) { log.error("SQLException occurred during events TTL task execution ", e); @@ -43,6 +45,7 @@ public class HsqlEventCleanupRepository extends JpaAbstractDaoListeningExecutorS try (Connection connection = dataSource.getConnection(); PreparedStatement stmt = connection.prepareStatement("DELETE FROM event WHERE ts < ? AND (event_type = 'DEBUG_RULE_NODE' OR event_type = 'DEBUG_RULE_CHAIN')")) { stmt.setLong(1, debugExpirationTime); + stmt.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(1)); stmt.execute(); } catch (SQLException e) { log.error("SQLException occurred during events TTL task execution ", e); From 72213235eb5d227cff3cd9df38ac2f7a33247580 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 23 Sep 2021 21:07:06 +0300 Subject: [PATCH 056/303] delay node is deprecated --- .../org/thingsboard/rule/engine/delay/TbMsgDelayNode.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index 4a3113baca..17cdae53b8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -38,10 +38,10 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; @Slf4j @RuleNode( type = ComponentType.ACTION, - name = "delay", + name = "delay (deprecated)", configClazz = TbMsgDelayNodeConfiguration.class, - nodeDescription = "Delays incoming message", - nodeDetails = "Delays messages for configurable period. Please note, this node acknowledges the message from the current queue (message will be removed from queue)", + nodeDescription = "Delays incoming message (deprecated)", + nodeDetails = "Deprecated! Delays messages for configurable period. Please note, this node acknowledges the message from the current queue (message will be removed from queue)", icon = "pause", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeMsgDelayConfig" From 041582b9c7bf9fd851047df8c6f66a799c82c2e1 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Wed, 13 Oct 2021 10:28:22 +0300 Subject: [PATCH 057/303] entity relation controller description --- .../server/controller/BaseController.java | 6 + .../controller/EntityRelationController.java | 139 ++++++++++++++---- .../server/common/data/id/EntityId.java | 5 + .../common/data/relation/EntityRelation.java | 12 +- .../data/relation/EntityRelationInfo.java | 4 + .../data/relation/EntityRelationsQuery.java | 5 + .../relation/RelationEntityTypeFilter.java | 5 + .../relation/RelationsSearchParameters.java | 4 +- 8 files changed, 145 insertions(+), 35 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index f1e8f06d5e..c93c387572 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -169,6 +169,8 @@ public abstract class BaseController { public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String ASSET_ID_PARAM_DESCRIPTION = "A string value representing the asset id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ENTITY_ID_PARAM_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; protected final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -188,11 +190,15 @@ public abstract class BaseController { protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; protected final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; + protected final String RELATION_INFO_DESCRIPTION = "Relation Info is an extension of the default Relation object that contains information about the 'from' and 'to' entity names. "; protected final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; protected final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; + protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; + protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; protected static final String HOME_DASHBOARD = "homeDashboardId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 3f072b77f0..dd14777997 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -15,7 +15,10 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -52,10 +55,16 @@ public class EntityRelationController extends BaseController { public static final String RELATION_TYPE = "relationType"; public static final String TO_ID = "toId"; + @ApiOperation(value = "Create Relation (saveRelation)", + notes = "Creates a relation between two entities in the platform. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that 'from' and 'to' entities are owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the 'from' and 'to' entities are assigned to the same customer.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) - public void saveRelation(@RequestBody EntityRelation relation) throws ThingsboardException { + public void saveRelation(@ApiParam(value = "A JSON value representing the relation.") + @RequestBody EntityRelation relation) throws ThingsboardException { try { checkNotNull(relation); checkEntityId(relation.getFrom(), Operation.WRITE); @@ -80,14 +89,20 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Delete Relation (deleteRelation)", + notes = "Deletes a relation between two entities in the platform. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that 'from' and 'to' entities are owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the 'from' and 'to' entities are assigned to the same customer.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE}) @ResponseStatus(value = HttpStatus.OK) - public void deleteRelation(@RequestParam(FROM_ID) String strFromId, - @RequestParam(FROM_TYPE) String strFromType, - @RequestParam(RELATION_TYPE) String strRelationType, - @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup, - @RequestParam(TO_ID) String strToId, @RequestParam(TO_TYPE) String strToType) throws ThingsboardException { + public void deleteRelation(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, + @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION) @RequestParam(RELATION_TYPE) String strRelationType, + @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup, + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException { checkParameter(FROM_ID, strFromId); checkParameter(FROM_TYPE, strFromType); checkParameter(RELATION_TYPE, strRelationType); @@ -119,11 +134,16 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Delete Relations (deleteRelations)", + notes = "Deletes all the relation (both 'from' and 'to' direction) for the specified entity. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that entity is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"id", "type"}) + @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"entityId", "entityType"}) @ResponseStatus(value = HttpStatus.OK) - public void deleteRelations(@RequestParam("entityId") String strId, - @RequestParam("entityType") String strType) throws ThingsboardException { + public void deleteRelations(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam("entityId") String strId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam("entityType") String strType) throws ThingsboardException { checkParameter("entityId", strId); checkParameter("entityType", strType); EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId); @@ -137,14 +157,21 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Get Relation (getRelation)", + notes = "Returns relation object between two specified entities if present. Otherwise throws exception." + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that 'from' and 'to' entities are owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the 'from' and 'to' entities are assigned to the same customer.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE}) @ResponseBody - public EntityRelation getRelation(@RequestParam(FROM_ID) String strFromId, - @RequestParam(FROM_TYPE) String strFromType, - @RequestParam(RELATION_TYPE) String strRelationType, - @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup, - @RequestParam(TO_ID) String strToId, @RequestParam(TO_TYPE) String strToType) throws ThingsboardException { + public EntityRelation getRelation(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, + @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION) @RequestParam(RELATION_TYPE) String strRelationType, + @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup, + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException { try { checkParameter(FROM_ID, strFromId); checkParameter(FROM_TYPE, strFromType); @@ -162,11 +189,18 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Get List of Relations (findByFrom)", + notes = "Returns list of relation objects for the specified entity by the 'from' direction. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that the entity is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE}) @ResponseBody - public List findByFrom(@RequestParam(FROM_ID) String strFromId, - @RequestParam(FROM_TYPE) String strFromType, + public List findByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, + @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(FROM_ID, strFromId); checkParameter(FROM_TYPE, strFromType); @@ -180,11 +214,18 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Get List of Relation Infos (findInfoByFrom)", + notes = "Returns list of relation info objects for the specified entity by the 'from' direction. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that the entity is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer. " + RELATION_INFO_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE}) @ResponseBody - public List findInfoByFrom(@RequestParam(FROM_ID) String strFromId, - @RequestParam(FROM_TYPE) String strFromType, + public List findInfoByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, + @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(FROM_ID, strFromId); checkParameter(FROM_TYPE, strFromType); @@ -198,12 +239,19 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Get List of Relations (findByFrom)", + notes = "Returns list of relation objects for the specified entity by the 'from' direction and relation type. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that the entity is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE, RELATION_TYPE}) @ResponseBody - public List findByFrom(@RequestParam(FROM_ID) String strFromId, - @RequestParam(FROM_TYPE) String strFromType, - @RequestParam(RELATION_TYPE) String strRelationType, + public List findByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, + @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION) @RequestParam(RELATION_TYPE) String strRelationType, + @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(FROM_ID, strFromId); checkParameter(FROM_TYPE, strFromType); @@ -218,11 +266,18 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Get List of Relations (findByTo)", + notes = "Returns list of relation objects for the specified entity by the 'to' direction. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that the entity is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {TO_ID, TO_TYPE}) @ResponseBody - public List findByTo(@RequestParam(TO_ID) String strToId, - @RequestParam(TO_TYPE) String strToType, + public List findByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType, + @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(TO_ID, strToId); checkParameter(TO_TYPE, strToType); @@ -236,11 +291,18 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Get List of Relation Infos (findInfoByTo)", + notes = "Returns list of relation info objects for the specified entity by the 'to' direction. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that the entity is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer. " + RELATION_INFO_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {TO_ID, TO_TYPE}) @ResponseBody - public List findInfoByTo(@RequestParam(TO_ID) String strToId, - @RequestParam(TO_TYPE) String strToType, + public List findInfoByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType, + @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(TO_ID, strToId); checkParameter(TO_TYPE, strToType); @@ -254,12 +316,19 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Get List of Relations (findByTo)", + notes = "Returns list of relation objects for the specified entity by the 'to' direction and relation type. " + + "If the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + "If the user has the authority of 'Tenant Administrator', the server checks that the entity is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {TO_ID, TO_TYPE, RELATION_TYPE}) @ResponseBody - public List findByTo(@RequestParam(TO_ID) String strToId, - @RequestParam(TO_TYPE) String strToType, - @RequestParam(RELATION_TYPE) String strRelationType, + public List findByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType, + @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION) @RequestParam(RELATION_TYPE) String strRelationType, + @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(TO_ID, strToId); checkParameter(TO_TYPE, strToType); @@ -274,10 +343,15 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Find related entities (findByQuery)", + notes = "Returns all entities that are related to the specific entity. " + + "The entity id, relation type, entity types, depth of the search, and other query parameters defined using complex 'EntityRelationsQuery' object. " + + "See 'Model' tab of the Parameters for more info.", produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.POST) @ResponseBody - public List findByQuery(@RequestBody EntityRelationsQuery query) throws ThingsboardException { + public List findByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.") + @RequestBody EntityRelationsQuery query) throws ThingsboardException { checkNotNull(query); checkNotNull(query.getParameters()); checkNotNull(query.getFilters()); @@ -289,10 +363,15 @@ public class EntityRelationController extends BaseController { } } + @ApiOperation(value = "Find related entity infos (findInfoByQuery)", + notes = "Returns all entity infos that are related to the specific entity. " + + "The entity id, relation type, entity types, depth of the search, and other query parameters defined using complex 'EntityRelationsQuery' object. " + + "See 'Model' tab of the Parameters for more info. " + RELATION_INFO_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations/info", method = RequestMethod.POST) @ResponseBody - public List findInfoByQuery(@RequestBody EntityRelationsQuery query) throws ThingsboardException { + public List findInfoByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.") + @RequestBody EntityRelationsQuery query) throws ThingsboardException { checkNotNull(query); checkNotNull(query.getParameters()); checkNotNull(query.getFilters()); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java index 6057858fcd..73b4a5b28f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java @@ -18,6 +18,8 @@ package org.thingsboard.server.common.data.id; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.EntityType; import java.io.Serializable; @@ -29,12 +31,15 @@ import java.util.UUID; @JsonDeserialize(using = EntityIdDeserializer.class) @JsonSerialize(using = EntityIdSerializer.class) +@ApiModel public interface EntityId extends HasUUID, Serializable { //NOSONAR, the constant is closely related to EntityId UUID NULL_UUID = UUID.fromString("13814000-1dd2-11b2-8080-808080808080"); + @ApiModelProperty(position = 1, required = true, value = "string", example = "784f394c-42b6-435a-983c-b7beff2784f9") UUID getId(); + @ApiModelProperty(position = 2, required = true, value = "string", example = "DEVICE") EntityType getEntityType(); @JsonIgnore diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java index 7833acc050..d3ff9ff5ca 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java @@ -16,18 +16,17 @@ package org.thingsboard.server.common.data.relation; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.EntityId; -import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.Serializable; @Slf4j +@ApiModel public class EntityRelation implements Serializable { private static final long serialVersionUID = 2807343040519543363L; @@ -72,6 +71,7 @@ public class EntityRelation implements Serializable { this.additionalInfo = entityRelation.getAdditionalInfo(); } + @ApiModelProperty(position = 1, value = "JSON object with [from] Entity Id.", readOnly = true) public EntityId getFrom() { return from; } @@ -80,6 +80,7 @@ public class EntityRelation implements Serializable { this.from = from; } + @ApiModelProperty(position = 2, value = "JSON object with [to] Entity Id.", readOnly = true) public EntityId getTo() { return to; } @@ -88,6 +89,7 @@ public class EntityRelation implements Serializable { this.to = to; } + @ApiModelProperty(position = 3, value = "String value of relation type.", example = "Contains") public String getType() { return type; } @@ -96,6 +98,7 @@ public class EntityRelation implements Serializable { this.type = type; } + @ApiModelProperty(position = 4, value = "Represents the type group of the relation.", example = "COMMON") public RelationTypeGroup getTypeGroup() { return typeGroup; } @@ -104,6 +107,7 @@ public class EntityRelation implements Serializable { this.typeGroup = typeGroup; } + @ApiModelProperty(position = 5, value = "Additional parameters of the relation", dataType = "com.fasterxml.jackson.databind.JsonNode") public JsonNode getAdditionalInfo() { return SearchTextBasedWithAdditionalInfo.getJson(() -> additionalInfo, () -> additionalInfoBytes); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java index 614518d3f8..dc580312f8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.relation; +import io.swagger.annotations.ApiModelProperty; + public class EntityRelationInfo extends EntityRelation { private static final long serialVersionUID = 2807343097519543363L; @@ -30,6 +32,7 @@ public class EntityRelationInfo extends EntityRelation { super(entityRelation); } + @ApiModelProperty(position = 6, value = "Name of the entity for [from] direction.", readOnly = true, example = "A4B72CCDFF33") public String getFromName() { return fromName; } @@ -38,6 +41,7 @@ public class EntityRelationInfo extends EntityRelation { this.fromName = fromName; } + @ApiModelProperty(position = 7, value = "Name of the entity for [to] direction.", readOnly = true, example = "A4B72CCDFF35") public String getToName() { return toName; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationsQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationsQuery.java index 1a5415d3c7..ef3b4eab23 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationsQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationsQuery.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.relation; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.List; @@ -23,9 +25,12 @@ import java.util.List; * Created by ashvayka on 02.05.17. */ @Data +@ApiModel public class EntityRelationsQuery { + @ApiModelProperty(position = 2, value = "Main search parameters.") private RelationsSearchParameters parameters; + @ApiModelProperty(position = 1, value = "Main filters.") private List filters; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationEntityTypeFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationEntityTypeFilter.java index 1e817dda14..95926a73f1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationEntityTypeFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationEntityTypeFilter.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.relation; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import org.thingsboard.server.common.data.EntityType; @@ -26,9 +28,12 @@ import java.util.List; */ @Data @AllArgsConstructor +@ApiModel public class RelationEntityTypeFilter { + @ApiModelProperty(position = 1, value = "Type of the relation between root entity and other entity (e.g. 'Contains' or 'Manages').", example = "Contains") private String relationType; + @ApiModelProperty(position = 2, value = "Array of entity types to filter the related entities (e.g. 'DEVICE', 'ASSET').") private List entityTypes; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationsSearchParameters.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationsSearchParameters.java index f195840f3b..76e8415b5f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationsSearchParameters.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationsSearchParameters.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.relation; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; @@ -33,7 +34,7 @@ import java.util.UUID; @AllArgsConstructor public class RelationsSearchParameters { - @ApiModelProperty(position = 1, value = "Root entity id to start search from.") + @ApiModelProperty(position = 1, value = "Root entity id to start search from.", example = "784f394c-42b6-435a-983c-b7beff2784f9") private UUID rootId; @ApiModelProperty(position = 2, value = "Type of the root entity.") private EntityType rootType; @@ -59,6 +60,7 @@ public class RelationsSearchParameters { this.fetchLastLevelOnly = fetchLastLevelOnly; } + @JsonIgnore public EntityId getEntityId() { return EntityIdFactory.getByTypeAndUuid(rootType, rootId); } From 3fda67be480a803cbac368ae18b16b151b2ba97d Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 13 Oct 2021 12:42:00 +0300 Subject: [PATCH 058/303] swagger docs for Alarm Controller --- .../server/controller/AlarmController.java | 99 ++++++++++++++++--- .../server/controller/BaseController.java | 6 +- .../server/common/data/alarm/Alarm.java | 36 +++++++ .../server/common/data/alarm/AlarmInfo.java | 3 + 4 files changed, 127 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index 7bbc84fb32..ea19982f00 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -15,8 +15,11 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -55,11 +58,25 @@ import java.util.List; public class AlarmController extends BaseController { public static final String ALARM_ID = "alarmId"; + private static final String ALARM_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the alarm is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the alarm belongs to the customer. "; + private static final String ALARM_QUERY_SEARCH_STATUS_DESCRIPTION = "A string value representing one of the AlarmSearchStatus enumeration value"; + private static final String ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES = "ANY, ACTIVE, CLEARED, ACK, UNACK"; + private static final String ALARM_QUERY_STATUS_DESCRIPTION = "A string value representing one of the AlarmStatus enumeration value"; + private static final String ALARM_QUERY_STATUS_ALLOWABLE_VALUES = "ACTIVE_UNACK, ACTIVE_ACK, CLEARED_UNACK, CLEARED_ACK"; + private static final String ALARM_QUERY_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on of next alarm fields: type, severity or status"; + private static final String ALARM_QUERY_START_TIME_DESCRIPTION = "The start timestamp(milliseconds) of the search time range over the alarm object field: 'createdTime'."; + private static final String ALARM_QUERY_END_TIME_DESCRIPTION = "The end timestamp(milliseconds) of the search time range over the alarm object field: 'createdTime'."; + private static final String ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION = "A boolean value to specify if the alarm originator name will be " + + "filled in the AlarmInfo object field: 'originatorName' or will returns as null."; - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @ApiOperation(value = "Get Alarm (getAlarmById)", + notes = "Fetch the Alarm object based on the provided Alarm Id. " + ALARM_SECURITY_CHECK, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.GET) @ResponseBody - public Alarm getAlarmById(@PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { + public Alarm getAlarmById(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) + @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); @@ -69,10 +86,14 @@ public class AlarmController extends BaseController { } } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @ApiOperation(value = "Get Alarm Info (getAlarmInfoById)", + notes = "Fetch the Alarm Info object based on the provided Alarm Id. " + + ALARM_SECURITY_CHECK + ALARM_INFO_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/info/{alarmId}", method = RequestMethod.GET) @ResponseBody - public AlarmInfo getAlarmInfoById(@PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { + public AlarmInfo getAlarmInfoById(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) + @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); @@ -82,10 +103,14 @@ public class AlarmController extends BaseController { } } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @ApiOperation(value = "Create or update Alarm (saveAlarm)", + notes = "Creates or Updates the Alarm. Platform generates random Alarm Id during alarm creation. " + + "The Alarm Id will be present in the response. Specify the Alarm Id when you would like to update the Alarm. " + + "Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm", method = RequestMethod.POST) @ResponseBody - public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException { + public Alarm saveAlarm(@ApiParam(value = "A JSON value representing the alarm.") @RequestBody Alarm alarm) throws ThingsboardException { try { alarm.setTenantId(getCurrentUser().getTenantId()); @@ -106,10 +131,12 @@ public class AlarmController extends BaseController { } } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @ApiOperation(value = "Delete Alarm (deleteAlarm)", + notes = "Deletes the Alarm. Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.DELETE) @ResponseBody - public Boolean deleteAlarm(@PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { + public Boolean deleteAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); @@ -124,15 +151,17 @@ public class AlarmController extends BaseController { sendAlarmDeleteNotificationMsg(getTenantId(), alarmId, relatedEdgeIds, alarm); return alarmService.deleteAlarm(getTenantId(), alarmId); - } catch (Exception e) { + } catch (Exception e) { throw handleException(e); } } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @ApiOperation(value = "Acknowledge Alarm (ackAlarm)", + notes = "Acknowledge the Alarm. Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) - public void ackAlarm(@PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { + public void ackAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); @@ -149,10 +178,12 @@ public class AlarmController extends BaseController { } } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @ApiOperation(value = "Clear Alarm (clearAlarm)", + notes = "Clear the Alarm. Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) - public void clearAlarm(@PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { + public void clearAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); @@ -169,21 +200,36 @@ public class AlarmController extends BaseController { } } + @ApiOperation(value = "Get Alarms (getAlarms)", + notes = "Returns a page of alarms for the selected entity. Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error. " + + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET) @ResponseBody public PageData getAlarms( + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String strEntityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String strEntityId, + @ApiParam(value = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String searchStatus, + @ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String status, + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = ALARM_QUERY_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, + @ApiParam(value = ALARM_QUERY_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime, + @ApiParam(value = ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION) @RequestParam(required = false) Boolean fetchOriginator ) throws ThingsboardException { checkParameter("EntityId", strEntityId); @@ -204,20 +250,35 @@ public class AlarmController extends BaseController { throw handleException(e); } } - - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @ApiOperation(value = "Get All Alarms (getAllAlarms)", + notes = "Returns a page of alarms that belongs to the current user owner. " + + "If the user has the authority of 'Tenant Administrator', the server returns alarms that belongs to the tenant of current user. " + + "If the user has the authority of 'Customer User', the server returns alarms that belongs to the customer of current user. " + + "Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error. " + + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarms", method = RequestMethod.GET) @ResponseBody public PageData getAllAlarms( + @ApiParam(value = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String searchStatus, + @ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String status, + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = ALARM_QUERY_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, + @ApiParam(value = ALARM_QUERY_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime, + @ApiParam(value = ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION) @RequestParam(required = false) Boolean fetchOriginator ) throws ThingsboardException { AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus); @@ -239,13 +300,19 @@ public class AlarmController extends BaseController { } } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @ApiOperation(value = "Get Highest Alarm Severity (getHighestAlarmSeverity)", + notes = "Returns highest AlarmSeverity object for the selected entity.", produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET) @ResponseBody public AlarmSeverity getHighestAlarmSeverity( + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String strEntityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String strEntityId, + @ApiParam(value = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String searchStatus, + @ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String status ) throws ThingsboardException { checkParameter("EntityId", strEntityId); diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index f1e8f06d5e..64eeaa3509 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -168,7 +168,7 @@ public abstract class BaseController { public static final String EDGE_ID_PARAM_DESCRIPTION = "A string value representing the edge id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String ASSET_ID_PARAM_DESCRIPTION = "A string value representing the asset id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - + public static final String ALARM_ID_PARAM_DESCRIPTION = "A string value representing the alarm id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -188,11 +188,15 @@ public abstract class BaseController { protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; protected final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; + protected final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that contains information about alarm originator name."; protected final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; protected final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; + protected static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; + protected static final String ENTITY_ID_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; protected static final String HOME_DASHBOARD = "homeDashboardId"; 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 54f7ab72f5..76560b212f 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 @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.alarm; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -39,18 +40,35 @@ import java.util.List; @AllArgsConstructor public class Alarm extends BaseData implements HasName, HasTenantId, HasCustomerId { + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id", readOnly = true) private TenantId tenantId; + + @ApiModelProperty(position = 4, value = "JSON object with Customer Id", readOnly = true) private CustomerId customerId; + + @ApiModelProperty(position = 6, required = true, value = "representing type of the Alarm", example = "High Temperature Alarm") private String type; + @ApiModelProperty(position = 7, required = true, value = "JSON object with alarm originator id") private EntityId originator; + @ApiModelProperty(position = 8, required = true, value = "Alarm severity", example = "CRITICAL") private AlarmSeverity severity; + @ApiModelProperty(position = 9, required = true, value = "Alarm status", example = "CLEARED_UNACK") private AlarmStatus status; + @ApiModelProperty(position = 10, value = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565") private long startTs; + @ApiModelProperty(position = 11, value = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522") private long endTs; + @ApiModelProperty(position = 12, value = "Timestamp of the alarm acknowledgement, in milliseconds", example = "1634115221948") private long ackTs; + @ApiModelProperty(position = 13, value = "Timestamp of the alarm clearing, in milliseconds", example = "1634114528465") private long clearTs; + @ApiModelProperty(position = 14, value = "JSON object with alarm details") private transient JsonNode details; + @ApiModelProperty(position = 15, value = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true") private boolean propagate; + @ApiModelProperty(position = 16, value = "JSON array of relation types that should be used for propagation. " + + "By default, 'propagateRelationTypes' array is empty which means that the alarm will propagate based on any relation type to parent entities. " + + "This parameter should be used only in case when 'propagate' parameter is set to true, otherwise, 'propagateRelationTypes' array will ignoned.") private List propagateRelationTypes; public Alarm() { @@ -81,7 +99,25 @@ public class Alarm extends BaseData implements HasName, HasTenantId, Ha @Override @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @ApiModelProperty(position = 5, required = true, value = "representing type of the Alarm", example = "High Temperature Alarm") public String getName() { return type; } + + @ApiModelProperty(position = 1, value = "JSON object with the alarm Id. " + + "Specify this field to update the alarm. " + + "Referencing non-existing alarm Id will cause error. " + + "Omit this field to create new alarm." ) + @Override + public AlarmId getId() { + return super.getId(); + } + + + @ApiModelProperty(position = 2, value = "Timestamp of the alarm creation, in milliseconds", example = "1634058704567", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java index 80d2b21ecb..45fd7bf70b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java @@ -15,10 +15,13 @@ */ package org.thingsboard.server.common.data.alarm; +import io.swagger.annotations.ApiModelProperty; + public class AlarmInfo extends Alarm { private static final long serialVersionUID = 2807343093519543363L; + @ApiModelProperty(position = 17, value = "Alarm originator name", example = "Thermostat") private String originatorName; public AlarmInfo() { From a126b888da64ec8d9fc5144c39509b00f9702398 Mon Sep 17 00:00:00 2001 From: Mariia Synelnyk <44849051+Mariesnlk@users.noreply.github.com> Date: Wed, 13 Oct 2021 12:47:49 +0300 Subject: [PATCH 059/303] add docs for audit-log controller (#12) * added swagger docs for audit logs controller * add api mpdel to AuditLog class * added produces to @ApiOperation in AuditLogController --- .../server/controller/AuditLogController.java | 55 +++++++++++++++++++ .../server/controller/BaseController.java | 4 +- .../server/common/data/audit/AuditLog.java | 13 +++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java index b9d9c6ba15..977b953bcc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java @@ -15,7 +15,10 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.apache.commons.lang3.StringUtils; +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -44,18 +47,35 @@ import java.util.stream.Collectors; @RequestMapping("/api") public class AuditLogController extends BaseController { + protected final String AUDIT_LOG_ACTION_TYPES_DESCRIPTION = "A String value representing action types parameter. The value is not required, but it can be any value of ActionType class. " + + "For example, 'ADDED,DELETED,UPDATED,LOGIN,LOGOUT'."; + protected final String SORT_AUDIT_LOG_PROPERTY_DESCRIPTION = "Property of logs to sort by"; + protected final String SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityName, entityType, user, type, status"; + + @ApiOperation(value = "Get audit logs by customer id (getAuditLogsByCustomerId)", + notes = "Returns a page of audit logs by selected customer. " + PAGE_DATA_PARAMETERS, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getAuditLogsByCustomerId( + @ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION) @PathVariable("customerId") String strCustomerId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = "The case insensitive 'startsWith' filter based on the customer name.") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_AUDIT_LOG_PROPERTY_DESCRIPTION, allowableValues = SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") @RequestParam(required = false) Long startTime, + @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") @RequestParam(required = false) Long endTime, + @ApiParam(value = AUDIT_LOG_ACTION_TYPES_DESCRIPTION) @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { try { checkParameter("CustomerId", strCustomerId); @@ -68,18 +88,30 @@ public class AuditLogController extends BaseController { } } + @ApiOperation(value = "Get audit logs by user id (getAuditLogsByUserId)", + notes = "Returns a page of audit logs by selected user. " + PAGE_DATA_PARAMETERS, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/user/{userId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getAuditLogsByUserId( + @ApiParam(value = USER_ID_PARAM_DESCRIPTION) @PathVariable("userId") String strUserId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = "The case insensitive 'startsWith' filter based on the user name.") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_AUDIT_LOG_PROPERTY_DESCRIPTION, allowableValues = SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") @RequestParam(required = false) Long startTime, + @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") @RequestParam(required = false) Long endTime, + @ApiParam(value = AUDIT_LOG_ACTION_TYPES_DESCRIPTION) @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { try { checkParameter("UserId", strUserId); @@ -92,19 +124,32 @@ public class AuditLogController extends BaseController { } } + @ApiOperation(value = "Get audit logs by entity id (getAuditLogsByEntityId)", + notes = "Returns a page of audit logs by selected entity. " + PAGE_DATA_PARAMETERS, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getAuditLogsByEntityId( + @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @PathVariable("entityType") String strEntityType, + @ApiParam(value = ENTITY_ID_DESCRIPTION) @PathVariable("entityId") String strEntityId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = "The case insensitive 'startsWith' filter based on the entity name.") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_AUDIT_LOG_PROPERTY_DESCRIPTION, allowableValues = SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") @RequestParam(required = false) Long startTime, + @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") @RequestParam(required = false) Long endTime, + @ApiParam(value = AUDIT_LOG_ACTION_TYPES_DESCRIPTION) @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { try { checkParameter("EntityId", strEntityId); @@ -118,17 +163,27 @@ public class AuditLogController extends BaseController { } } + @ApiOperation(value = "Get all audit logs (getAuditLogs)", + notes = "Returns a page of all audit logs. " + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getAuditLogs( + @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, + @ApiParam(value = "The case insensitive 'startsWith' filter based on any name like 'Device', 'Asset', 'Customer' etc.") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_AUDIT_LOG_PROPERTY_DESCRIPTION, allowableValues = SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") @RequestParam(required = false) Long startTime, + @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") @RequestParam(required = false) Long endTime, + @ApiParam(value = AUDIT_LOG_ACTION_TYPES_DESCRIPTION) @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index ad54aaf526..33ac4ef181 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -162,6 +162,7 @@ public abstract class BaseController { public static final String TENANT_ID_PARAM_DESCRIPTION = "A string value representing the tenant id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String EDGE_ID_PARAM_DESCRIPTION = "A string value representing the edge id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String USER_ID_PARAM_DESCRIPTION = "A string value representing the user id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -174,7 +175,8 @@ public abstract class BaseController { protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; - + protected static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; + protected static final String ENTITY_ID_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java b/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java index 1ce0d6af02..8b714ca61d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java @@ -16,24 +16,37 @@ package org.thingsboard.server.common.data.audit; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.id.*; +@ApiModel @EqualsAndHashCode(callSuper = true) @Data public class AuditLog extends BaseData { + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", readOnly = true) private TenantId tenantId; + @ApiModelProperty(position = 2, value = "JSON object with Customer Id.", readOnly = true) private CustomerId customerId; + @ApiModelProperty(position = 3, value = "JSON object with Entity id.", readOnly = true) private EntityId entityId; + @ApiModelProperty(position = 4, value = "Entity Name", example = "Thermometer", readOnly = true) private String entityName; + @ApiModelProperty(position = 5, value = "JSON object with User id.", readOnly = true) private UserId userId; + @ApiModelProperty(position = 6, value = "Unique User Name in scope of Administrator.", example = "Tenant", readOnly = true) private String userName; + @ApiModelProperty(position = 7, value = "String represented Action type.", readOnly = true) private ActionType actionType; + @ApiModelProperty(position = 8, value = "JsonNode represented action data.", readOnly = true) private JsonNode actionData; + @ApiModelProperty(position = 9, value = "string", example = "SUCCESS", allowableValues = "SUCCESS,FAILURE", readOnly = true) private ActionStatus actionStatus; + @ApiModelProperty(position = 10, value = "Action failure details info", readOnly = true) private String actionFailureDetails; public AuditLog() { From d1974e9b04b9cfeb46a7b0d3c975fead32094a51 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Wed, 13 Oct 2021 13:19:08 +0300 Subject: [PATCH 060/303] swagger description for event controller --- .../server/controller/BaseController.java | 7 +++ .../server/controller/EventController.java | 46 ++++++++++++++++++- .../thingsboard/server/common/data/Event.java | 13 ++++++ .../server/common/data/event/DebugEvent.java | 2 + .../data/event/DebugRuleChainEventFilter.java | 3 ++ .../data/event/DebugRuleNodeEventFilter.java | 3 ++ .../common/data/event/ErrorEventFilter.java | 2 + .../server/common/data/event/EventFilter.java | 3 +- .../data/event/LifeCycleEventFilter.java | 2 + .../data/event/StatisticsEventFilter.java | 2 + 10 files changed, 81 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index f1e8f06d5e..2fba9e1bc8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -169,6 +169,8 @@ public abstract class BaseController { public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String ASSET_ID_PARAM_DESCRIPTION = "A string value representing the asset id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ENTITY_ID_PARAM_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ENTITY_TYPE_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; protected final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -179,11 +181,13 @@ public abstract class BaseController { protected final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; protected final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; protected final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; + protected final String EVENT_TEXT_SEARCH_DESCRIPTION = "The value is not used in searching."; protected final String SORT_PROPERTY_DESCRIPTION = "Property of entity to sort by"; protected final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title"; protected final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; protected final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; protected final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; + protected final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; protected final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; @@ -193,6 +197,9 @@ public abstract class BaseController { protected final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; protected final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; + protected final String EVENT_START_TIME_DESCRIPTION = "Timestamp. Events with creation time before it won't be queried."; + protected final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; protected static final String HOME_DASHBOARD = "homeDashboardId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 7e49ba55d4..8127b4b2cf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -15,7 +15,10 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -45,20 +48,34 @@ public class EventController extends BaseController { @Autowired private EventService eventService; + @ApiOperation(value = "Get Events (getEvents)", + notes = "Returns a page of events for specified entity by specifying event type." + + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}", method = RequestMethod.GET) @ResponseBody public PageData getEvents( + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @PathVariable("entityType") String strEntityType, + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String strEntityId, + @ApiParam(value = "A string value representing event type", example = "STATS", required = true) @PathVariable("eventType") String eventType, + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true) @RequestParam("tenantId") String strTenantId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = EVENT_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EVENT_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = EVENT_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, + @ApiParam(value = EVENT_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime) throws ThingsboardException { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); @@ -74,19 +91,32 @@ public class EventController extends BaseController { } } + @ApiOperation(value = "Get Events (getEvents)", + notes = "Returns a page of events for specified entity." + + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.GET) @ResponseBody public PageData getEvents( + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @PathVariable("entityType") String strEntityType, + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String strEntityId, + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true) @RequestParam("tenantId") String strTenantId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = EVENT_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EVENT_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = EVENT_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, + @ApiParam(value = EVENT_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime) throws ThingsboardException { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); @@ -104,20 +134,34 @@ public class EventController extends BaseController { } } + @ApiOperation(value = "Get Events (getEvents)", + notes = "Returns a page of events for specified entity by specifying event filter." + + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.POST) @ResponseBody public PageData getEvents( + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @PathVariable("entityType") String strEntityType, + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String strEntityId, + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true) @RequestParam("tenantId") String strTenantId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = "A JSON value representing the event filter.", required = true) @RequestBody EventFilter eventFilter, + @ApiParam(value = EVENT_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EVENT_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, + @ApiParam(value = EVENT_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, + @ApiParam(value = EVENT_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime) throws ThingsboardException { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); @@ -127,7 +171,7 @@ public class EventController extends BaseController { EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); checkEntityId(entityId, Operation.READ); - if(sortProperty != null && sortProperty.equals("createdTime") && eventFilter.hasFilterForJsonBody()) { + if (sortProperty != null && sortProperty.equals("createdTime") && eventFilter.hasFilterForJsonBody()) { sortProperty = ModelConstants.CREATED_TIME_PROPERTY; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Event.java b/common/data/src/main/java/org/thingsboard/server/common/data/Event.java index f218ef9929..915bebfdb5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Event.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Event.java @@ -16,6 +16,8 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EventId; @@ -25,12 +27,18 @@ import org.thingsboard.server.common.data.id.TenantId; * @author Andrew Shvayka */ @Data +@ApiModel public class Event extends BaseData { + @ApiModelProperty(position = 1, value = "JSON object with Tenant Id.", readOnly = true) private TenantId tenantId; + @ApiModelProperty(position = 2, value = "Event type", example = "STATS") private String type; + @ApiModelProperty(position = 3, value = "string", example = "784f394c-42b6-435a-983c-b7beff2784f9") private String uid; + @ApiModelProperty(position = 4, value = "JSON object with Entity Id for which event is created.", readOnly = true) private EntityId entityId; + @ApiModelProperty(position = 5, value = "Event body.", dataType = "com.fasterxml.jackson.databind.JsonNode") private transient JsonNode body; public Event() { @@ -45,4 +53,9 @@ public class Event extends BaseData { super(event); } + @ApiModelProperty(position = 6, value = "Timestamp of the event creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java index a95949acbd..4af40ba971 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java @@ -15,10 +15,12 @@ */ package org.thingsboard.server.common.data.event; +import io.swagger.annotations.ApiModel; import lombok.Data; import org.thingsboard.server.common.data.StringUtils; @Data +@ApiModel public abstract class DebugEvent implements EventFilter { private String msgDirectionType; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleChainEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleChainEventFilter.java index cc16d780f0..60e28f3b6f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleChainEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleChainEventFilter.java @@ -15,6 +15,9 @@ */ package org.thingsboard.server.common.data.event; +import io.swagger.annotations.ApiModel; + +@ApiModel public class DebugRuleChainEventFilter extends DebugEvent { @Override public EventType getEventType() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleNodeEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleNodeEventFilter.java index abe73e6e85..42d04be1ee 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleNodeEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleNodeEventFilter.java @@ -15,6 +15,9 @@ */ package org.thingsboard.server.common.data.event; +import io.swagger.annotations.ApiModel; + +@ApiModel public class DebugRuleNodeEventFilter extends DebugEvent { @Override public EventType getEventType() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java index c9e9886c64..69c44d5a5d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java @@ -15,10 +15,12 @@ */ package org.thingsboard.server.common.data.event; +import io.swagger.annotations.ApiModel; import lombok.Data; import org.thingsboard.server.common.data.StringUtils; @Data +@ApiModel public class ErrorEventFilter implements EventFilter { private String server; private String method; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java index eebab7e7d4..ff8aa40be2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java @@ -16,10 +16,11 @@ package org.thingsboard.server.common.data.event; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.annotations.ApiModel; +@ApiModel @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java index a871ccb106..906cac6f6e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java @@ -15,10 +15,12 @@ */ package org.thingsboard.server.common.data.event; +import io.swagger.annotations.ApiModel; import lombok.Data; import org.thingsboard.server.common.data.StringUtils; @Data +@ApiModel public class LifeCycleEventFilter implements EventFilter { private String server; private String event; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java index 9fad8b4bca..50848076b4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java @@ -15,10 +15,12 @@ */ package org.thingsboard.server.common.data.event; +import io.swagger.annotations.ApiModel; import lombok.Data; import org.thingsboard.server.common.data.StringUtils; @Data +@ApiModel public class StatisticsEventFilter implements EventFilter { private String server; private Integer messagesProcessed; From 4be37230ce0e73a8d1c0513f4b4412defbafa16d Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 13 Oct 2021 13:24:50 +0300 Subject: [PATCH 061/303] fix typos --- .../org/thingsboard/server/controller/AlarmController.java | 4 ++-- .../org/thingsboard/server/controller/BaseController.java | 1 + .../java/org/thingsboard/server/common/data/alarm/Alarm.java | 2 ++ .../org/thingsboard/server/common/data/alarm/AlarmInfo.java | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index ea19982f00..fa50a1b7b5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -221,7 +221,7 @@ public class AlarmController extends BaseController { @RequestParam int page, @ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, @@ -270,7 +270,7 @@ public class AlarmController extends BaseController { @RequestParam int page, @ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 64eeaa3509..adc55fcb4f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -184,6 +184,7 @@ public abstract class BaseController { protected final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; protected final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; protected final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; + protected final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; protected final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; 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 76560b212f..cb73aeb5e0 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 @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.alarm; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -35,6 +36,7 @@ import java.util.List; /** * Created by ashvayka on 11.05.17. */ +@ApiModel @Data @Builder @AllArgsConstructor diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java index 45fd7bf70b..6919159424 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java @@ -15,8 +15,10 @@ */ package org.thingsboard.server.common.data.alarm; +import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +@ApiModel public class AlarmInfo extends Alarm { private static final long serialVersionUID = 2807343093519543363L; From d17ea19bbadb2cae4394814ce71e02354eef139e Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Wed, 13 Oct 2021 13:36:00 +0300 Subject: [PATCH 062/303] added required fields --- .../controller/EntityRelationController.java | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index dd14777997..ec6e401dec 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -63,7 +63,7 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) - public void saveRelation(@ApiParam(value = "A JSON value representing the relation.") + public void saveRelation(@ApiParam(value = "A JSON value representing the relation.", required = true) @RequestBody EntityRelation relation) throws ThingsboardException { try { checkNotNull(relation); @@ -97,12 +97,12 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE}) @ResponseStatus(value = HttpStatus.OK) - public void deleteRelation(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, - @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION) @RequestParam(RELATION_TYPE) String strRelationType, + public void deleteRelation(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType, + @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType, @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup, - @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException { + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException { checkParameter(FROM_ID, strFromId); checkParameter(FROM_TYPE, strFromType); checkParameter(RELATION_TYPE, strRelationType); @@ -142,8 +142,8 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"entityId", "entityType"}) @ResponseStatus(value = HttpStatus.OK) - public void deleteRelations(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam("entityId") String strId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam("entityType") String strType) throws ThingsboardException { + public void deleteRelations(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam("entityId") String strId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam("entityType") String strType) throws ThingsboardException { checkParameter("entityId", strId); checkParameter("entityType", strType); EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId); @@ -166,12 +166,12 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE}) @ResponseBody - public EntityRelation getRelation(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, - @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION) @RequestParam(RELATION_TYPE) String strRelationType, + public EntityRelation getRelation(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType, + @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType, @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup, - @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException { + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException { try { checkParameter(FROM_ID, strFromId); checkParameter(FROM_TYPE, strFromType); @@ -198,8 +198,8 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE}) @ResponseBody - public List findByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, + public List findByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType, @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(FROM_ID, strFromId); @@ -223,8 +223,8 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE}) @ResponseBody - public List findInfoByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, + public List findInfoByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType, @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(FROM_ID, strFromId); @@ -248,9 +248,9 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE, RELATION_TYPE}) @ResponseBody - public List findByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(FROM_ID) String strFromId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(FROM_TYPE) String strFromType, - @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION) @RequestParam(RELATION_TYPE) String strRelationType, + public List findByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType, + @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType, @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(FROM_ID, strFromId); @@ -275,8 +275,8 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {TO_ID, TO_TYPE}) @ResponseBody - public List findByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType, + public List findByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType, @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(TO_ID, strToId); @@ -300,8 +300,8 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {TO_ID, TO_TYPE}) @ResponseBody - public List findInfoByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType, + public List findInfoByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType, @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(TO_ID, strToId); @@ -325,9 +325,9 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {TO_ID, TO_TYPE, RELATION_TYPE}) @ResponseBody - public List findByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @RequestParam(TO_ID) String strToId, - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) @RequestParam(TO_TYPE) String strToType, - @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION) @RequestParam(RELATION_TYPE) String strRelationType, + public List findByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId, + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType, + @ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType, @ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(TO_ID, strToId); @@ -350,7 +350,7 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.POST) @ResponseBody - public List findByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.") + public List findByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.", required = true) @RequestBody EntityRelationsQuery query) throws ThingsboardException { checkNotNull(query); checkNotNull(query.getParameters()); @@ -370,7 +370,7 @@ public class EntityRelationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations/info", method = RequestMethod.POST) @ResponseBody - public List findInfoByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.") + public List findInfoByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.", required = true) @RequestBody EntityRelationsQuery query) throws ThingsboardException { checkNotNull(query); checkNotNull(query.getParameters()); From f47e1c7e3700b30dc6e30e9c205c4ce59f180a9b Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 13 Oct 2021 15:19:57 +0300 Subject: [PATCH 063/303] Alarm Swagger Docs --- .../server/controller/AlarmController.java | 40 ++++++++++++------- .../server/controller/BaseController.java | 2 +- .../server/controller/DeviceController.java | 3 +- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index fa50a1b7b5..addf343191 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -58,8 +58,8 @@ import java.util.List; public class AlarmController extends BaseController { public static final String ALARM_ID = "alarmId"; - private static final String ALARM_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the alarm is owned by the same tenant. " + - "If the user has the authority of 'Customer User', the server checks that the alarm belongs to the customer. "; + private static final String ALARM_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the originator of alarm is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the originator of alarm belongs to the customer. "; private static final String ALARM_QUERY_SEARCH_STATUS_DESCRIPTION = "A string value representing one of the AlarmSearchStatus enumeration value"; private static final String ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES = "ANY, ACTIVE, CLEARED, ACK, UNACK"; private static final String ALARM_QUERY_STATUS_DESCRIPTION = "A string value representing one of the AlarmStatus enumeration value"; @@ -104,9 +104,15 @@ public class AlarmController extends BaseController { } @ApiOperation(value = "Create or update Alarm (saveAlarm)", - notes = "Creates or Updates the Alarm. Platform generates random Alarm Id during alarm creation. " + - "The Alarm Id will be present in the response. Specify the Alarm Id when you would like to update the Alarm. " + - "Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Creates or Updates the Alarm. " + + "When creating alarm, platform generates Alarm Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created Alarm id will be present in the response. Specify existing Alarm id to update the alarm. " + + "Referencing non-existing Alarm Id will cause 'Not Found' error. " + + "\n\nPlatform also deduplicate the alarms based on the entity id of originator and alarm 'type'. " + + "For example, if the user or system component create the alarm with the type 'HighTemperature' for device 'Device A' the new active alarm is created. " + + "If the user tries to create 'HighTemperature' alarm for the same device again, the previous alarm will be updated (the 'end_ts' will be set to current timestamp). " + + "If the user clears the alarm (see 'Clear Alarm(clearAlarm)'), than new alarm with the same type and same device may be created. " + , produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm", method = RequestMethod.POST) @ResponseBody @@ -157,7 +163,9 @@ public class AlarmController extends BaseController { } @ApiOperation(value = "Acknowledge Alarm (ackAlarm)", - notes = "Acknowledge the Alarm. Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Acknowledge the Alarm. " + + "Once acknowledged, the 'ack_ts' field will be set to current timestamp and special rule chain event 'ALARM_ACK' will be generated. " + + "Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @@ -179,7 +187,9 @@ public class AlarmController extends BaseController { } @ApiOperation(value = "Clear Alarm (clearAlarm)", - notes = "Clear the Alarm. Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Clear the Alarm. " + + "Once cleared, the 'clear_ts' field will be set to current timestamp and special rule chain event 'ALARM_CLEAR' will be generated. " + + "Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @@ -215,9 +225,9 @@ public class AlarmController extends BaseController { @RequestParam(required = false) String searchStatus, @ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String status, - @ApiParam(value = PAGE_SIZE_DESCRIPTION) + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION) + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, @@ -264,9 +274,9 @@ public class AlarmController extends BaseController { @RequestParam(required = false) String searchStatus, @ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String status, - @ApiParam(value = PAGE_SIZE_DESCRIPTION) + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION) + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, @@ -301,14 +311,16 @@ public class AlarmController extends BaseController { } @ApiOperation(value = "Get Highest Alarm Severity (getHighestAlarmSeverity)", - notes = "Returns highest AlarmSeverity object for the selected entity.", produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Search the alarms by originator ('entityType' and entityId') and optional 'status' or 'searchStatus' filters and returns the highest AlarmSeverity(CRITICAL, MAJOR, MINOR, WARNING or INDETERMINATE). " + + "Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error." + , produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET) @ResponseBody public AlarmSeverity getHighestAlarmSeverity( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) + @ApiParam(value = ENTITY_TYPE_DESCRIPTION, required = true) @PathVariable("entityType") String strEntityType, - @ApiParam(value = ENTITY_ID_DESCRIPTION) + @ApiParam(value = ENTITY_ID_DESCRIPTION, required = true) @PathVariable("entityId") String strEntityId, @ApiParam(value = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String searchStatus, diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index adc55fcb4f..601f73fe0f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -189,7 +189,7 @@ public abstract class BaseController { protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; protected final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; - protected final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that contains information about alarm originator name."; + protected final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that also contains name of the alarm originator."; protected final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; 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 f0991ff901..ed88cbc78b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -141,7 +141,8 @@ public class DeviceController extends BaseController { "Device credentials are also generated if not provided in the 'accessToken' request parameter. " + "The newly created device id will be present in the response. " + "Specify existing Device id to update the device. " + - "Referencing non-existing device Id will cause 'Not Found' error.") + "Referencing non-existing device Id will cause 'Not Found' error." + + "\n\nDevice name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the device names and non-unique 'label' field for user-friendly visualization purposes.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device", method = RequestMethod.POST) @ResponseBody From d473a5b85e4d5e0b6d0992dce1b7eb2d7cfc9655 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 13 Oct 2021 16:09:36 +0300 Subject: [PATCH 064/303] Fixed Photo Camera input error if entity is empty --- .../widget/lib/photo-camera-input.component.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.ts index c791b88589..b752d73b67 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.ts @@ -117,6 +117,7 @@ export class PhotoCameraInputWidgetComponent extends PageComponent implements On updatePhoto = false; previewPhoto: SafeUrl; lastPhoto: SafeUrl; + datasourceDetected = false; private static hasGetUserMedia(): boolean { return !!(window.navigator.mediaDevices && window.navigator.mediaDevices.getUserMedia); @@ -148,14 +149,16 @@ export class PhotoCameraInputWidgetComponent extends PageComponent implements On this.width = this.settings.maxWidth ? this.settings.maxWidth : 640; this.height = this.settings.maxHeight ? this.settings.maxWidth : 480; - - if (this.datasource.type === DatasourceType.entity) { - if (this.datasource.entityType && this.datasource.entityId) { - this.isEntityDetected = true; + this.datasourceDetected = this.ctx.datasources?.length !== 0; + if (this.datasourceDetected) { + if (this.datasource.type === DatasourceType.entity) { + if (this.datasource.entityType && this.datasource.entityId) { + this.isEntityDetected = true; + } + } + if (this.datasource.dataKeys.length) { + this.dataKeyDetected = true; } - } - if (this.datasource.dataKeys.length) { - this.dataKeyDetected = true; } this.detectAvailableDevices(); } From 2d4ac40e25a2495ee4427ecf73ef4c3c9fe6040b Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 13 Oct 2021 16:51:49 +0300 Subject: [PATCH 065/303] Refactor searchTenantIdRecursive for rule chains import --- .../org/thingsboard/server/dao/rule/BaseRuleChainService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index fa1c4ec173..487f39f2cc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -481,7 +481,9 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } if (isTenantId) { ObjectNode objNode = (ObjectNode) node; - objNode.put("id", tenantId.getId().toString()); + if (objNode.has("id")) { + objNode.put("id", tenantId.getId().toString()); + } } else { for (JsonNode jsonNode : node) { searchTenantIdRecursive(tenantId, jsonNode); From 54411f08644c23e03099d4dc3b38cf46e0b9f86b Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Thu, 14 Oct 2021 10:51:12 +0300 Subject: [PATCH 066/303] fixing typos --- .../thingsboard/server/controller/EventController.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 8a4902ed91..560520e228 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -48,8 +48,8 @@ public class EventController extends BaseController { @Autowired private EventService eventService; - @ApiOperation(value = "Get Events (getEvents)", - notes = "Returns a page of events for specified entity by specifying event type." + + @ApiOperation(value = "Get Events by type (getEvents)", + notes = "Returns a page of events for specified entity by specifying event type. " + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}", method = RequestMethod.GET) @@ -92,7 +92,7 @@ public class EventController extends BaseController { } @ApiOperation(value = "Get Events (getEvents)", - notes = "Returns a page of events for specified entity." + + notes = "Returns a page of events for specified entity. " + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.GET) @@ -134,8 +134,8 @@ public class EventController extends BaseController { } } - @ApiOperation(value = "Get Events (getEvents)", - notes = "Returns a page of events for specified entity by specifying event filter." + + @ApiOperation(value = "Get Events by event filter (getEvents)", + notes = "Returns a page of events for specified entity by specifying event filter. " + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.POST) From 19e18f8272c10fa20f3509fc09126a377f29cf58 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Thu, 14 Oct 2021 11:13:35 +0300 Subject: [PATCH 067/303] fixing typos in entity relation controller --- .../server/controller/EntityRelationController.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index f83ad8399e..435ac4f89b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -59,17 +59,14 @@ public class EntityRelationController extends BaseController { "If the user has the authority of 'Tenant Administrator', the server checks that 'from' and 'to' entities are owned by the same tenant. " + "If the user has the authority of 'Customer User', the server checks that the 'from' and 'to' entities are assigned to the same customer."; - private static final String SECURITY_CHECKS_ENTITY_DESCRIPTION = "\n\nIf the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + + private static final String SECURITY_CHECKS_ENTITY_DESCRIPTION = "\n\nIf the user has the authority of 'System Administrator', the server checks that the entity is owned by the sysadmin. " + "If the user has the authority of 'Tenant Administrator', the server checks that the entity is owned by the same tenant. " + "If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer."; - @ApiOperation(value = "Create Relation (saveRelation)", notes = "Creates or updates a relation between two entities in the platform. " + "Relations unique key is a combination of from/to entity id and relation type group and relation type. " + - "\n\nIf the user has the authority of 'System Administrator', the server checks that 'from' and 'to' entities are owned by the sysadmin. " + - "If the user has the authority of 'Tenant Administrator', the server checks that 'from' and 'to' entities are owned by the same tenant. " + - "If the user has the authority of 'Customer User', the server checks that the 'from' and 'to' entities are assigned to the same customer.") + SECURITY_CHECKS_ENTITIES_DESCRIPTION) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @@ -163,7 +160,7 @@ public class EntityRelationController extends BaseController { } @ApiOperation(value = "Get Relation (getRelation)", - notes = "Returns relation object between two specified entities if present. Otherwise throws exception." + SECURITY_CHECKS_ENTITIES_DESCRIPTION, + notes = "Returns relation object between two specified entities if present. Otherwise throws exception. " + SECURITY_CHECKS_ENTITIES_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE}) @@ -216,7 +213,7 @@ public class EntityRelationController extends BaseController { @ApiOperation(value = "Get List of Relation Infos (findInfoByFrom)", notes = "Returns list of relation info objects for the specified entity by the 'from' direction. " + - SECURITY_CHECKS_ENTITY_DESCRIPTION +" " + RELATION_INFO_DESCRIPTION, + SECURITY_CHECKS_ENTITY_DESCRIPTION + " " + RELATION_INFO_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE}) From 626437117de2d6b01fb4f32f4a733682ca00be11 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 14 Oct 2021 14:30:52 +0300 Subject: [PATCH 068/303] Added required config. Added produces config --- .../server/controller/BaseController.java | 2 + .../server/controller/EdgeController.java | 118 ++++++++++-------- .../controller/EdgeEventController.java | 11 +- 3 files changed, 75 insertions(+), 56 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 6bb01e6502..1d21b639a8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -194,12 +194,14 @@ public abstract class BaseController { protected final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; protected final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; + protected final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; protected final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; protected final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that also contains name of the alarm originator."; protected final String RELATION_INFO_DESCRIPTION = "Relation Info is an extension of the default Relation object that contains information about the 'from' and 'to' entity names. "; + protected final String EDGE_INFO_DESCRIPTION = "Edge Info is an extension of the default Edge object that contains information about the assigned customer name. "; protected final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; protected final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index da8efc5bde..4c8e21de99 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -22,6 +22,7 @@ import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -90,11 +91,12 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Get Edge (getEdgeById)", - notes = "Get the Edge object based on the provided Edge Id. " + EDGE_SECURITY_CHECK) + notes = "Get the Edge object based on the provided Edge Id. " + EDGE_SECURITY_CHECK, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET) @ResponseBody - public Edge getEdgeById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + public Edge getEdgeById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { @@ -110,11 +112,12 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Get Edge Info (getEdgeInfoById)", - notes = "Get the Edge Info object based on the provided Edge Id. " + EDGE_SECURITY_CHECK) + notes = "Get the Edge Info object based on the provided Edge Id. " + EDGE_SECURITY_CHECK, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/info/{edgeId}", method = RequestMethod.GET) @ResponseBody - public EdgeInfo getEdgeInfoById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + public EdgeInfo getEdgeInfoById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { @@ -130,13 +133,16 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Create Or Update Edge (saveEdge)", - notes = "Creates or Updates the Edge. Platform generates random Edge Id during edge creation. " + - "The edge id will be present in the response. " + - "Specify the Edge id when you would like to update the edge. Referencing non-existing edge Id will cause an error.") + notes = "Create or update the Edge. When creating edge, platform generates Edge Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created edge id will be present in the response. " + + "Specify existing Edge id to update the edge. " + + "Referencing non-existing Edge Id will cause 'Not Found' error." + + "\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge", method = RequestMethod.POST) @ResponseBody - public Edge saveEdge(@ApiParam(value = "A JSON value representing the ed.") + public Edge saveEdge(@ApiParam(value = "A JSON value representing the ed.", required = true) @RequestBody Edge edge) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); @@ -185,7 +191,7 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + public void deleteEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { @@ -213,17 +219,17 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Tenant Edges (getEdges)", notes = "Returns a page of edges owned by tenant. " + - PAGE_DATA_PARAMETERS) + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public PageData getEdges(@ApiParam(value = PAGE_SIZE_DESCRIPTION) + public PageData getEdges(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION) + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { @@ -237,13 +243,14 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Assign edge to customer (assignEdgeToCustomer)", - notes = "Creates assignment of the edge to customer. Customer will be able to query edge afterwards.") + notes = "Creates assignment of the edge to customer. Customer will be able to query edge afterwards.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST) @ResponseBody - public Edge assignEdgeToCustomer(@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION) + public Edge assignEdgeToCustomer(@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true) @PathVariable("customerId") String strCustomerId, - @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter("customerId", strCustomerId); checkParameter(EDGE_ID, strEdgeId); @@ -276,11 +283,12 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Unassign edge from customer (unassignEdgeFromCustomer)", - notes = "Clears assignment of the edge to customer. Customer will not be able to query edge afterwards.") + notes = "Clears assignment of the edge to customer. Customer will not be able to query edge afterwards.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE) @ResponseBody - public Edge unassignEdgeFromCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + public Edge unassignEdgeFromCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { @@ -315,11 +323,12 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Make edge publicly available (assignEdgeToPublicCustomer)", notes = "Edge will be available for non-authorized (not logged-in) users. " + "This is useful to create dashboards that you plan to share/embed on a publicly available website. " + - "However, users that are logged-in and belong to different tenant will not be able to access the edge.") + "However, users that are logged-in and belong to different tenant will not be able to access the edge.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST) @ResponseBody - public Edge assignEdgeToPublicCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + public Edge assignEdgeToPublicCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); try { @@ -346,20 +355,20 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Tenant Edges (getTenantEdges)", notes = "Returns a page of edges owned by tenant. " + - PAGE_DATA_PARAMETERS) + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getTenantEdges( - @ApiParam(value = PAGE_SIZE_DESCRIPTION) + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION) + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = EDGE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { @@ -378,20 +387,21 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Tenant Edge Infos (getTenantEdgeInfos)", notes = "Returns a page of edges info objects owned by tenant. " + - PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION) + PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getTenantEdgeInfos( - @ApiParam(value = PAGE_SIZE_DESCRIPTION) + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION) + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = EDGE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { @@ -410,11 +420,12 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Tenant Edge (getTenantEdge)", notes = "Requested edge must be owned by tenant or customer that the user belongs to. " + - "Edge name is an unique property of edge. So it can be used to identify the edge.") + "Edge name is an unique property of edge. So it can be used to identify the edge.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET) @ResponseBody - public Edge getTenantEdge(@ApiParam(value = "Unique name of the edge") + public Edge getTenantEdge(@ApiParam(value = "Unique name of the edge", required = true) @RequestParam String edgeName) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); @@ -425,14 +436,15 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Set root rule chain for provided edge (setRootRuleChain)", - notes = "Change root rule chain of the edge from the current to the new provided rule chain. \n" + - "This operation will send a notification to remote edge service to update root rule chain remotely.") + notes = "Change root rule chain of the edge to the new provided rule chain. \n" + + "This operation will send a notification to update root rule chain on remote edge service.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST) @ResponseBody - public Edge setRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + public Edge setRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(EDGE_ID) String strEdgeId, - @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true) @PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); checkParameter("ruleChainId", strRuleChainId); @@ -463,22 +475,22 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Customer Edges (getCustomerEdges)", notes = "Returns a page of edges objects assigned to customer. " + - PAGE_DATA_PARAMETERS) + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getCustomerEdges( @ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION) @PathVariable("customerId") String strCustomerId, - @ApiParam(value = PAGE_SIZE_DESCRIPTION) + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION) + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = EDGE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { @@ -508,22 +520,22 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Customer Edge Infos (getCustomerEdgeInfos)", notes = "Returns a page of edges info objects assigned to customer. " + - PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION) + PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getCustomerEdgeInfos( @ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION) @PathVariable("customerId") String strCustomerId, - @ApiParam(value = PAGE_SIZE_DESCRIPTION) + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION) + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = EDGE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, @ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { @@ -552,12 +564,13 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Get Edges By Ids (getEdgesByIds)", - notes = "Requested edges must be owned by tenant or assigned to customer which user is performing the request. ") + notes = "Requested edges must be owned by tenant or assigned to customer which user is performing the request.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) @ResponseBody public List getEdgesByIds( - @ApiParam(value = "A list of edges ids, separated by comma ','") + @ApiParam(value = "A list of edges ids, separated by comma ','", required = true) @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException { checkArrayParameter("edgeIds", strEdgeIds); try { @@ -588,8 +601,9 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Find related edges (findByQuery)", notes = "Returns all edges that are related to the specific entity. " + - "The entity id, relation type, device types, depth of the search, and other query parameters defined using complex 'EdgeSearchQuery' object. " + - "See 'Model' tab of the Parameters for more info.") + "The entity id, relation type, edge types, depth of the search, and other query parameters defined using complex 'EdgeSearchQuery' object. " + + "See 'Model' tab of the Parameters for more info.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges", method = RequestMethod.POST) @ResponseBody @@ -622,7 +636,8 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Get Edge Types (getEdgeTypes)", - notes = "Returns a set of unique edge types based on edges that are either owned by the tenant or assigned to the customer which user is performing the request.") + notes = "Returns a set of unique edge types based on edges that are either owned by the tenant or assigned to the customer which user is performing the request.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/types", method = RequestMethod.GET) @ResponseBody @@ -642,7 +657,7 @@ public class EdgeController extends BaseController { "All entities that are assigned to particular edge are going to be send to remote edge service.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/sync/{edgeId}", method = RequestMethod.POST) - public void syncEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + public void syncEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("edgeId") String strEdgeId) throws ThingsboardException { checkParameter("edgeId", strEdgeId); try { @@ -661,11 +676,11 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Find missing rule chains (findMissingToRelatedRuleChains)", - notes = "Returns list of rule chains ids that are not assigned to particular edge, but these rule chains are present in the already assigned rule chains to edge") + notes = "Returns list of rule chains ids that are not assigned to particular edge, but these rule chains are present in the already assigned rule chains to edge.") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/missingToRelatedRuleChains/{edgeId}", method = RequestMethod.GET) @ResponseBody - public String findMissingToRelatedRuleChains(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + public String findMissingToRelatedRuleChains(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("edgeId") String strEdgeId) throws ThingsboardException { try { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); @@ -679,7 +694,8 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Import the bulk of edges (processEdgesBulkImport)", - notes = "There's an ability to import the bulk of edges using the only .csv file.") + notes = "There's an ability to import the bulk of edges using the only .csv file.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PostMapping("/edge/bulk_import") public BulkImportResult processEdgesBulkImport(@RequestBody BulkImportRequest request) throws Exception { diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java index 13fafd4eed..e688ab1375 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java @@ -19,6 +19,7 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -49,20 +50,20 @@ public class EdgeEventController extends BaseController { @ApiOperation(value = "Get Edge Events (getEdgeEvents)", notes = "Returns a page of edge events for the requested edge. " + - PAGE_DATA_PARAMETERS) + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/events", method = RequestMethod.GET) @ResponseBody public PageData getEdgeEvents( - @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) + @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(EDGE_ID) String strEdgeId, - @ApiParam(value = PAGE_SIZE_DESCRIPTION) + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION) + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = "The case insensitive 'startsWith' filter based on the edge event type name.") @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, From 0670652897e62181178fd6c5eeba1ddf1964c867 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Thu, 14 Oct 2021 18:11:03 +0300 Subject: [PATCH 069/303] event filters description --- .../server/controller/BaseController.java | 8 +++ .../server/controller/EventController.java | 18 ++++-- .../common/data/event/BaseEventFilter.java | 57 +++++++++++++++++++ .../server/common/data/event/DebugEvent.java | 17 +----- .../common/data/event/ErrorEventFilter.java | 9 +-- .../server/common/data/event/EventFilter.java | 5 +- .../data/event/LifeCycleEventFilter.java | 10 +--- .../data/event/StatisticsEventFilter.java | 7 +-- .../server/dao/sql/event/JpaBaseEventDao.java | 10 +--- ui-ngx/src/app/shared/models/event.models.ts | 6 +- 10 files changed, 95 insertions(+), 52 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/event/BaseEventFilter.java diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 64a1dd00d3..12d9e53a2a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -203,6 +203,14 @@ public abstract class BaseController { protected final String EVENT_START_TIME_DESCRIPTION = "Timestamp. Events with creation time before it won't be queried."; protected final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; + + protected final String EVENT_ERROR_FILTER_OBJ = "{ \"eventType\": \"ERROR\", \"server\": \"ip-172-31-24-152\", \"method\": \"onClusterEventMsg\", \"error\": \"Error Message\" }"; + protected final String EVENT_LC_EVENT_FILTER_OBJ = "{ \"eventType\": \"LC_EVENT\", \"server\": \"ip-172-31-24-152\", \"event\": \"STARTED\", \"status\": \"Success\", \"error\": \"Error Message\" }"; + protected final String EVENT_STATS_FILTER_OBJ = "{ \"eventType\": \"STATS\", \"server\": \"ip-172-31-24-152\", \"messagesProcessed\": 10, \"errorsOccurred\": 5 }"; + protected final String DEBUG_FILTER_OBJ = "\"msgDirectionType\": \"IN\", \"server\": \"ip-172-31-24-152\", \"dataSearch\": \"humidity\", \"metadataSearch\": \"deviceName\", \"entityName\": \"DEVICE\", \"relationType\": \"Success\", \"entityId\": \"de9d54a0-2b7a-11ec-a3cc-23386423d98f\", \"msgType\": \"POST_TELEMETRY_REQUEST\", \"isError\": \"false\", \"error\": \"Error Message\" }"; + protected final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ; + protected final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ; + protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 560520e228..097e18d406 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -28,7 +28,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Event; -import org.thingsboard.server.common.data.event.EventFilter; +import org.thingsboard.server.common.data.event.BaseEventFilter; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -45,6 +45,8 @@ import org.thingsboard.server.service.security.permission.Operation; @RequestMapping("/api") public class EventController extends BaseController { + private static final String NEW_LINE = "\n\n"; + @Autowired private EventService eventService; @@ -135,8 +137,16 @@ public class EventController extends BaseController { } @ApiOperation(value = "Get Events by event filter (getEvents)", - notes = "Returns a page of events for specified entity by specifying event filter. " + - PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Returns a page of events for the chosen entity by specifying the event filter. " + + PAGE_DATA_PARAMETERS + NEW_LINE + "5 different eventFilter objects could be set for different event types. " + + "The eventType field is required. Others are optional. If some of them are set, the filtering will be applied according to them. " + + "See the examples below for all the fields used for each event type filtering. " + NEW_LINE + + EVENT_ERROR_FILTER_OBJ + NEW_LINE + + EVENT_LC_EVENT_FILTER_OBJ + NEW_LINE + + EVENT_STATS_FILTER_OBJ + NEW_LINE + + EVENT_DEBUG_RULE_NODE_FILTER_OBJ + NEW_LINE + + EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ + NEW_LINE, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.POST) @ResponseBody @@ -152,7 +162,7 @@ public class EventController extends BaseController { @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = "A JSON value representing the event filter.", required = true) - @RequestBody EventFilter eventFilter, + @RequestBody BaseEventFilter eventFilter, @ApiParam(value = EVENT_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EVENT_SORT_PROPERTY_ALLOWABLE_VALUES) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/BaseEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/BaseEventFilter.java new file mode 100644 index 0000000000..cd3335b17f --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/BaseEventFilter.java @@ -0,0 +1,57 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.event; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel +@Data +public abstract class BaseEventFilter implements EventFilter { + + @ApiModelProperty(position = 1, value = "String value representing msg direction type (incoming to entity or outcoming from entity)", allowableValues = "IN, OUT") + protected String msgDirectionType; + @ApiModelProperty(position = 2, value = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152") + protected String server; + @ApiModelProperty(position = 3, value = "The case insensitive 'contains' filter based on data (key and value) for the message.", example = "humidity") + protected String dataSearch; + @ApiModelProperty(position = 4, value = "The case insensitive 'contains' filter based on metadata (key and value) for the message.", example = "deviceName") + protected String metadataSearch; + @ApiModelProperty(position = 5, value = "String value representing the entity type", allowableValues = "DEVICE") + protected String entityName; + @ApiModelProperty(position = 6, value = "String value representing the type of message routing", example = "Success") + protected String relationType; + @ApiModelProperty(position = 7, value = "String value representing the entity id in the event body (originator of the message)", example = "de9d54a0-2b7a-11ec-a3cc-23386423d98f") + protected String entityId; + @ApiModelProperty(position = 8, value = "String value representing the message type", example = "POST_TELEMETRY_REQUEST") + protected String msgType; + @ApiModelProperty(position = 9, value = "Boolean value to filter the errors", allowableValues = "false, true") + protected boolean isError; + @ApiModelProperty(position = 10, value = "The case insensitive 'contains' filter based on error message", example = "not present in the DB") + protected String errorStr; + @ApiModelProperty(position = 11, value = "String value representing the method name when the error happened", example = "onClusterEventMsg") + protected String method; + @ApiModelProperty(position = 12, value = "The minimum number of successfully processed messages", example = "25") + protected Integer messagesProcessed; + @ApiModelProperty(position = 13, value = "The minimum number of errors occurred during messages processing", example = "30") + protected Integer errorsOccurred; + @ApiModelProperty(position = 14, value = "String value representing the lifecycle event type", example = "STARTED") + protected String event; + @ApiModelProperty(position = 15, value = "String value representing status of the lifecycle event", allowableValues = "Success, Failure") + protected String status; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java index 4af40ba971..f318b40c0b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java @@ -16,23 +16,10 @@ package org.thingsboard.server.common.data.event; import io.swagger.annotations.ApiModel; -import lombok.Data; import org.thingsboard.server.common.data.StringUtils; -@Data @ApiModel -public abstract class DebugEvent implements EventFilter { - - private String msgDirectionType; - private String server; - private String dataSearch; - private String metadataSearch; - private String entityName; - private String relationType; - private String entityId; - private String msgType; - private boolean isError; - private String error; +public abstract class DebugEvent extends BaseEventFilter implements EventFilter { public void setIsError(boolean isError) { this.isError = isError; @@ -41,7 +28,7 @@ public abstract class DebugEvent implements EventFilter { @Override public boolean hasFilterForJsonBody() { return !StringUtils.isEmpty(msgDirectionType) || !StringUtils.isEmpty(server) || !StringUtils.isEmpty(dataSearch) || !StringUtils.isEmpty(metadataSearch) - || !StringUtils.isEmpty(entityName) || !StringUtils.isEmpty(relationType) || !StringUtils.isEmpty(entityId) || !StringUtils.isEmpty(msgType) || !StringUtils.isEmpty(error) || isError; + || !StringUtils.isEmpty(entityName) || !StringUtils.isEmpty(relationType) || !StringUtils.isEmpty(entityId) || !StringUtils.isEmpty(msgType) || !StringUtils.isEmpty(errorStr) || isError; } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java index 69c44d5a5d..6a41f110b4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java @@ -16,15 +16,10 @@ package org.thingsboard.server.common.data.event; import io.swagger.annotations.ApiModel; -import lombok.Data; import org.thingsboard.server.common.data.StringUtils; -@Data @ApiModel -public class ErrorEventFilter implements EventFilter { - private String server; - private String method; - private String error; +public class ErrorEventFilter extends BaseEventFilter implements EventFilter { @Override public EventType getEventType() { @@ -33,6 +28,6 @@ public class ErrorEventFilter implements EventFilter { @Override public boolean hasFilterForJsonBody() { - return !StringUtils.isEmpty(server) || !StringUtils.isEmpty(method) || !StringUtils.isEmpty(error); + return !StringUtils.isEmpty(server) || !StringUtils.isEmpty(method) || !StringUtils.isEmpty(errorStr); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java index ff8aa40be2..872b8a0095 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java @@ -15,10 +15,10 @@ */ package org.thingsboard.server.common.data.event; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; @ApiModel @JsonTypeInfo( @@ -33,7 +33,8 @@ import io.swagger.annotations.ApiModel; @JsonSubTypes.Type(value = StatisticsEventFilter.class, name = "STATS") }) public interface EventFilter { - @JsonIgnore + + @ApiModelProperty(position = 1, required = true, value = "String value representing the event type", example = "STATS") EventType getEventType(); boolean hasFilterForJsonBody(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java index 906cac6f6e..dcdce9422a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java @@ -16,16 +16,10 @@ package org.thingsboard.server.common.data.event; import io.swagger.annotations.ApiModel; -import lombok.Data; import org.thingsboard.server.common.data.StringUtils; -@Data @ApiModel -public class LifeCycleEventFilter implements EventFilter { - private String server; - private String event; - private String status; - private String error; +public class LifeCycleEventFilter extends BaseEventFilter implements EventFilter { @Override public EventType getEventType() { @@ -34,6 +28,6 @@ public class LifeCycleEventFilter implements EventFilter { @Override public boolean hasFilterForJsonBody() { - return !StringUtils.isEmpty(server) || !StringUtils.isEmpty(event) || !StringUtils.isEmpty(status) || !StringUtils.isEmpty(error); + return !StringUtils.isEmpty(server) || !StringUtils.isEmpty(event) || !StringUtils.isEmpty(status) || !StringUtils.isEmpty(errorStr); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java index 50848076b4..3e2635da97 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java @@ -16,15 +16,10 @@ package org.thingsboard.server.common.data.event; import io.swagger.annotations.ApiModel; -import lombok.Data; import org.thingsboard.server.common.data.StringUtils; -@Data @ApiModel -public class StatisticsEventFilter implements EventFilter { - private String server; - private Integer messagesProcessed; - private Integer errorsOccurred; +public class StatisticsEventFilter extends BaseEventFilter implements EventFilter { @Override public EventType getEventType() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java index c35247ad21..78741a9c1d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java @@ -39,10 +39,6 @@ import org.thingsboard.server.dao.event.EventDao; import org.thingsboard.server.dao.model.sql.EventEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -196,7 +192,7 @@ public class JpaBaseEventDao extends JpaAbstractDao implemen eventFilter.getEntityId(), eventFilter.getMsgType(), eventFilter.isError(), - eventFilter.getError(), + eventFilter.getErrorStr(), eventFilter.getDataSearch(), eventFilter.getMetadataSearch(), DaoUtil.toPageable(pageLink))); @@ -212,7 +208,7 @@ public class JpaBaseEventDao extends JpaAbstractDao implemen notNull(pageLink.getEndTime()), eventFilter.getServer(), eventFilter.getMethod(), - eventFilter.getError(), + eventFilter.getErrorStr(), DaoUtil.toPageable(pageLink)) ); } @@ -231,7 +227,7 @@ public class JpaBaseEventDao extends JpaAbstractDao implemen eventFilter.getEvent(), statusFilterEnabled, statusFilter, - eventFilter.getError(), + eventFilter.getErrorStr(), DaoUtil.toPageable(pageLink)) ); } diff --git a/ui-ngx/src/app/shared/models/event.models.ts b/ui-ngx/src/app/shared/models/event.models.ts index ac7d87c0c4..4970c3b83e 100644 --- a/ui-ngx/src/app/shared/models/event.models.ts +++ b/ui-ngx/src/app/shared/models/event.models.ts @@ -91,13 +91,13 @@ export interface BaseFilterEventBody { export interface ErrorFilterEventBody extends BaseFilterEventBody { method?: string; - error?: string; + errorStr?: string; } export interface LcFilterEventEventBody extends BaseFilterEventBody { event?: string; status?: string; - error?: string; + errorStr?: string; } export interface StatsFilterEventBody extends BaseFilterEventBody { @@ -115,7 +115,7 @@ export interface DebugFilterRuleNodeEventBody extends BaseFilterEventBody { dataSearch?: string; metadataSearch?: string; isError?: boolean; - error?: string; + errorStr?: string; } export type FilterEventBody = ErrorFilterEventBody & LcFilterEventEventBody & StatsFilterEventBody & DebugFilterRuleNodeEventBody; From 2e6b839a41624a3057f2229d586a55ac183c391f Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 14 Oct 2021 19:39:00 +0300 Subject: [PATCH 070/303] added swagger docs for audit log controller --- .../server/controller/AlarmController.java | 4 +- .../server/controller/AuditLogController.java | 74 +++++++++++-------- .../server/controller/BaseController.java | 8 +- .../server/controller/CustomerController.java | 2 +- .../server/common/data/audit/AuditLog.java | 33 ++++++--- 5 files changed, 76 insertions(+), 45 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index 0500338e72..a0942ab8ff 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -65,8 +65,8 @@ public class AlarmController extends BaseController { private static final String ALARM_QUERY_STATUS_DESCRIPTION = "A string value representing one of the AlarmStatus enumeration value"; private static final String ALARM_QUERY_STATUS_ALLOWABLE_VALUES = "ACTIVE_UNACK, ACTIVE_ACK, CLEARED_UNACK, CLEARED_ACK"; private static final String ALARM_QUERY_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on of next alarm fields: type, severity or status"; - private static final String ALARM_QUERY_START_TIME_DESCRIPTION = "The start timestamp(milliseconds) of the search time range over the alarm object field: 'createdTime'."; - private static final String ALARM_QUERY_END_TIME_DESCRIPTION = "The end timestamp(milliseconds) of the search time range over the alarm object field: 'createdTime'."; + private static final String ALARM_QUERY_START_TIME_DESCRIPTION = "The start timestamp in milliseconds of the search time range over the Alarm class field: 'createdTime'."; + private static final String ALARM_QUERY_END_TIME_DESCRIPTION = "The end timestamp in milliseconds of the search time range over the Alarm class field: 'createdTime'."; private static final String ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION = "A boolean value to specify if the alarm originator name will be " + "filled in the AlarmInfo object field: 'originatorName' or will returns as null."; diff --git a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java index 977b953bcc..f94ce73a2f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java @@ -47,13 +47,20 @@ import java.util.stream.Collectors; @RequestMapping("/api") public class AuditLogController extends BaseController { - protected final String AUDIT_LOG_ACTION_TYPES_DESCRIPTION = "A String value representing action types parameter. The value is not required, but it can be any value of ActionType class. " + - "For example, 'ADDED,DELETED,UPDATED,LOGIN,LOGOUT'."; - protected final String SORT_AUDIT_LOG_PROPERTY_DESCRIPTION = "Property of logs to sort by"; - protected final String SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityName, entityType, user, type, status"; + private static final String AUDIT_LOG_QUERY_START_TIME_DESCRIPTION = "The start timestamp in milliseconds of the search time range over the AuditLog class field: 'createdTime'."; + private static final String AUDIT_LOG_QUERY_END_TIME_DESCRIPTION = "The end timestamp in milliseconds of the search time range over the AuditLog class field: 'createdTime'."; + private static final String AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION = "A String value representing comma-separated list of action types. " + + "This parameter is optional, but it can be used to filter results to fetch only audit logs of specific action types. " + + "For example, 'LOGIN', 'LOGOUT'. See the 'Model' tab of the Response Class for more details."; + private static final String AUDIT_LOG_SORT_PROPERTY_DESCRIPTION = "Property of audit log to sort by. " + + "See the 'Model' tab of the Response Class for more details. " + + "Note: entityType sort property is not defined in the AuditLog class, however, it can be used to sort audit logs by types of entities that were logged."; + @ApiOperation(value = "Get audit logs by customer id (getAuditLogsByCustomerId)", - notes = "Returns a page of audit logs by selected customer. " + PAGE_DATA_PARAMETERS, + notes = "Returns a page of audit logs related to the targeted customer entities(devices, assets, etc.), " + + "and users actions(login, logout, etc.) that belong to this customer. " + + PAGE_DATA_PARAMETERS + ADMINISTRATOR_AUTHORITY_ONLY, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -65,17 +72,17 @@ public class AuditLogController extends BaseController { @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, - @ApiParam(value = "The case insensitive 'startsWith' filter based on the customer name.") + @ApiParam(value = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_AUDIT_LOG_PROPERTY_DESCRIPTION, allowableValues = SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, allowableValues = AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, - @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") + @ApiParam(value = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, - @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") + @ApiParam(value = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime, - @ApiParam(value = AUDIT_LOG_ACTION_TYPES_DESCRIPTION) + @ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION) @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { try { checkParameter("CustomerId", strCustomerId); @@ -89,7 +96,9 @@ public class AuditLogController extends BaseController { } @ApiOperation(value = "Get audit logs by user id (getAuditLogsByUserId)", - notes = "Returns a page of audit logs by selected user. " + PAGE_DATA_PARAMETERS, + notes = "Returns a page of audit logs related to the actions of targeted user. " + + "For example, RPC call to a particular device, or alarm acknowledgment for a specific device, etc. " + + PAGE_DATA_PARAMETERS + ADMINISTRATOR_AUTHORITY_ONLY, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/user/{userId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -101,17 +110,17 @@ public class AuditLogController extends BaseController { @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, - @ApiParam(value = "The case insensitive 'startsWith' filter based on the user name.") + @ApiParam(value = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_AUDIT_LOG_PROPERTY_DESCRIPTION, allowableValues = SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, allowableValues = AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, - @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") + @ApiParam(value = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, - @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") + @ApiParam(value = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime, - @ApiParam(value = AUDIT_LOG_ACTION_TYPES_DESCRIPTION) + @ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION) @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { try { checkParameter("UserId", strUserId); @@ -125,31 +134,34 @@ public class AuditLogController extends BaseController { } @ApiOperation(value = "Get audit logs by entity id (getAuditLogsByEntityId)", - notes = "Returns a page of audit logs by selected entity. " + PAGE_DATA_PARAMETERS, + notes = "Returns a page of audit logs related to the actions on the targeted entity. " + + "Basically, this API call is used to get the full lifecycle of some specific entity. " + + "For example to see when a device was created, updated, assigned to some customer, or even deleted from the system. " + + PAGE_DATA_PARAMETERS + ADMINISTRATOR_AUTHORITY_ONLY, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getAuditLogsByEntityId( - @ApiParam(value = ENTITY_TYPE_DESCRIPTION) + @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION) @PathVariable("entityType") String strEntityType, - @ApiParam(value = ENTITY_ID_DESCRIPTION) + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @PathVariable("entityId") String strEntityId, @ApiParam(value = PAGE_SIZE_DESCRIPTION) @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, - @ApiParam(value = "The case insensitive 'startsWith' filter based on the entity name.") + @ApiParam(value = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_AUDIT_LOG_PROPERTY_DESCRIPTION, allowableValues = SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, allowableValues = AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, - @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") + @ApiParam(value = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, - @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") + @ApiParam(value = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime, - @ApiParam(value = AUDIT_LOG_ACTION_TYPES_DESCRIPTION) + @ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION) @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { try { checkParameter("EntityId", strEntityId); @@ -164,7 +176,9 @@ public class AuditLogController extends BaseController { } @ApiOperation(value = "Get all audit logs (getAuditLogs)", - notes = "Returns a page of all audit logs. " + PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Returns a page of audit logs related to all entities in the scope of the current user's Tenant. " + + PAGE_DATA_PARAMETERS + ADMINISTRATOR_AUTHORITY_ONLY, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -173,17 +187,17 @@ public class AuditLogController extends BaseController { @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION) @RequestParam int page, - @ApiParam(value = "The case insensitive 'startsWith' filter based on any name like 'Device', 'Asset', 'Customer' etc.") + @ApiParam(value = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, - @ApiParam(value = SORT_AUDIT_LOG_PROPERTY_DESCRIPTION, allowableValues = SORT_AUDIT_LOG_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, allowableValues = AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder, - @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") + @ApiParam(value = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION) @RequestParam(required = false) Long startTime, - @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") + @ApiParam(value = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION) @RequestParam(required = false) Long endTime, - @ApiParam(value = AUDIT_LOG_ACTION_TYPES_DESCRIPTION) + @ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION) @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 2f9c5dc634..6c8a395c9b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -186,6 +186,7 @@ public abstract class BaseController { protected final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; protected final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; protected final String EVENT_TEXT_SEARCH_DESCRIPTION = "The value is not used in searching."; + protected final String AUDIT_LOG_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on one of the next properties: entityType, entityName, userName, actionType, actionStatus."; protected final String SORT_PROPERTY_DESCRIPTION = "Property of entity to sort by"; protected final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title"; protected final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; @@ -193,6 +194,7 @@ public abstract class BaseController { protected final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; protected final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; + protected final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; protected final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; @@ -205,8 +207,10 @@ public abstract class BaseController { protected final String EVENT_START_TIME_DESCRIPTION = "Timestamp. Events with creation time before it won't be queried."; protected final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; - protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; - protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; + protected final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; + protected final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; + + protected final String ADMINISTRATOR_AUTHORITY_ONLY = "Available for users with 'Tenant Administrator' authority only."; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index 335140949a..d1c5610bf0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -212,7 +212,7 @@ public class CustomerController extends BaseController { } @ApiOperation(value = "Get Tenant Customer by Customer title (getTenantCustomer)", - notes = "Get the Customer using Customer Title. Available for users with 'Tenant Administrator' authority only.") + notes = "Get the Customer using Customer Title. " + ADMINISTRATOR_AUTHORITY_ONLY) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/customers", params = {"customerTitle"}, method = RequestMethod.GET) @ResponseBody diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java b/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java index 8b714ca61d..2e259d7fa4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java @@ -28,25 +28,25 @@ import org.thingsboard.server.common.data.id.*; @Data public class AuditLog extends BaseData { - @ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", readOnly = true) + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id", readOnly = true) private TenantId tenantId; - @ApiModelProperty(position = 2, value = "JSON object with Customer Id.", readOnly = true) + @ApiModelProperty(position = 4, value = "JSON object with Customer Id", readOnly = true) private CustomerId customerId; - @ApiModelProperty(position = 3, value = "JSON object with Entity id.", readOnly = true) + @ApiModelProperty(position = 5, value = "JSON object with Entity id", readOnly = true) private EntityId entityId; - @ApiModelProperty(position = 4, value = "Entity Name", example = "Thermometer", readOnly = true) + @ApiModelProperty(position = 6, value = "Name of the logged entity", example = "Thermometer", readOnly = true) private String entityName; - @ApiModelProperty(position = 5, value = "JSON object with User id.", readOnly = true) + @ApiModelProperty(position = 7, value = "JSON object with User id.", readOnly = true) private UserId userId; - @ApiModelProperty(position = 6, value = "Unique User Name in scope of Administrator.", example = "Tenant", readOnly = true) + @ApiModelProperty(position = 8, value = "Unique user name(email) of the user that performed some action on logged entity", example = "tenant@thingsboard.org", readOnly = true) private String userName; - @ApiModelProperty(position = 7, value = "String represented Action type.", readOnly = true) + @ApiModelProperty(position = 9, value = "String represented Action type", example = "ADDED", readOnly = true) private ActionType actionType; - @ApiModelProperty(position = 8, value = "JsonNode represented action data.", readOnly = true) + @ApiModelProperty(position = 10, value = "JsonNode represented action data", readOnly = true) private JsonNode actionData; - @ApiModelProperty(position = 9, value = "string", example = "SUCCESS", allowableValues = "SUCCESS,FAILURE", readOnly = true) + @ApiModelProperty(position = 11, value = "String represented Action status", example = "SUCCESS", allowableValues = "SUCCESS,FAILURE", readOnly = true) private ActionStatus actionStatus; - @ApiModelProperty(position = 10, value = "Action failure details info", readOnly = true) + @ApiModelProperty(position = 12, value = "Failure action details info. An empty string in case of action status type 'SUCCESS', otherwise includes stack trace of the caused exception.", readOnly = true) private String actionFailureDetails; public AuditLog() { @@ -70,4 +70,17 @@ public class AuditLog extends BaseData { this.actionStatus = auditLog.getActionStatus(); this.actionFailureDetails = auditLog.getActionFailureDetails(); } + + @ApiModelProperty(position = 2, value = "Timestamp of the auditLog creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + + @ApiModelProperty(position = 1, value = "JSON object with the auditLog Id") + @Override + public AuditLogId getId() { + return super.getId(); + } + } From 3b5f11dfc10fc5c3463daf326427f1a1876e5732 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Thu, 14 Oct 2021 21:30:50 +0300 Subject: [PATCH 071/303] fixed error field on ui --- .../home/components/event/event-filter-panel.component.html | 4 ++-- .../app/modules/home/components/event/event-table-config.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/event/event-filter-panel.component.html b/ui-ngx/src/app/modules/home/components/event/event-filter-panel.component.html index 579301d086..98d83e3c79 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-filter-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/event/event-filter-panel.component.html @@ -44,10 +44,10 @@ {{ 'event.has-error' | translate }} - + {{ column.title | translate}} - + diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 49d8e87e44..9bf6912c9f 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -292,14 +292,14 @@ export class EventTableConfig extends EntityTableConfig { case EventType.ERROR: this.filterColumns.push( {key: 'method', title: 'event.method'}, - {key: 'error', title: 'event.error'} + {key: 'errorStr', title: 'event.error'} ); break; case EventType.LC_EVENT: this.filterColumns.push( {key: 'event', title: 'event.event'}, {key: 'status', title: 'event.status'}, - {key: 'error', title: 'event.error'} + {key: 'errorStr', title: 'event.error'} ); break; case EventType.STATS: @@ -319,7 +319,7 @@ export class EventTableConfig extends EntityTableConfig { {key: 'dataSearch', title: 'event.data'}, {key: 'metadataSearch', title: 'event.metadata'}, {key: 'isError', title: 'event.error'}, - {key: 'error', title: 'event.error'} + {key: 'errorStr', title: 'event.error'} ); break; } From e3bbfc71bf9b1f2f5e49ccf306211d32fb6d3d8a Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 15 Oct 2021 13:05:39 +0300 Subject: [PATCH 072/303] Improvement to contain the code block in examples --- .../server/controller/BaseController.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index ac4895c264..65d3fd25a8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -209,12 +209,19 @@ public abstract class BaseController { protected final String EVENT_START_TIME_DESCRIPTION = "Timestamp. Events with creation time before it won't be queried."; protected final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; - protected final String EVENT_ERROR_FILTER_OBJ = "{ \"eventType\": \"ERROR\", \"server\": \"ip-172-31-24-152\", \"method\": \"onClusterEventMsg\", \"error\": \"Error Message\" }"; - protected final String EVENT_LC_EVENT_FILTER_OBJ = "{ \"eventType\": \"LC_EVENT\", \"server\": \"ip-172-31-24-152\", \"event\": \"STARTED\", \"status\": \"Success\", \"error\": \"Error Message\" }"; - protected final String EVENT_STATS_FILTER_OBJ = "{ \"eventType\": \"STATS\", \"server\": \"ip-172-31-24-152\", \"messagesProcessed\": 10, \"errorsOccurred\": 5 }"; - protected final String DEBUG_FILTER_OBJ = "\"msgDirectionType\": \"IN\", \"server\": \"ip-172-31-24-152\", \"dataSearch\": \"humidity\", \"metadataSearch\": \"deviceName\", \"entityName\": \"DEVICE\", \"relationType\": \"Success\", \"entityId\": \"de9d54a0-2b7a-11ec-a3cc-23386423d98f\", \"msgType\": \"POST_TELEMETRY_REQUEST\", \"isError\": \"false\", \"error\": \"Error Message\" }"; - protected final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ; - protected final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ; + protected final String MARKDOWN_CODE_BLOCK_START = "```json\n"; + protected final String MARKDOWN_CODE_BLOCK_END = "\n```"; + protected final String EVENT_ERROR_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"ERROR\", \"server\": \"ip-172-31-24-152\", " + + "\"method\": \"onClusterEventMsg\", \"error\": \"Error Message\" }" + MARKDOWN_CODE_BLOCK_END; + protected final String EVENT_LC_EVENT_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"LC_EVENT\", \"server\": \"ip-172-31-24-152\", \"event\":" + + " \"STARTED\", \"status\": \"Success\", \"error\": \"Error Message\" }" + MARKDOWN_CODE_BLOCK_END; + protected final String EVENT_STATS_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"STATS\", \"server\": \"ip-172-31-24-152\", \"messagesProcessed\": 10, \"errorsOccurred\": 5 }" + MARKDOWN_CODE_BLOCK_END; + protected final String DEBUG_FILTER_OBJ = "\"msgDirectionType\": \"IN\", \"server\": \"ip-172-31-24-152\", \"dataSearch\": \"humidity\", " + + "\"metadataSearch\": \"deviceName\", \"entityName\": \"DEVICE\", \"relationType\": \"Success\"," + + " \"entityId\": \"de9d54a0-2b7a-11ec-a3cc-23386423d98f\", \"msgType\": \"POST_TELEMETRY_REQUEST\"," + + " \"isError\": \"false\", \"error\": \"Error Message\" }"; + protected final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; + protected final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; From 2c0f013625aa75b26a0b4592eb653a75a05b22da Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 15 Oct 2021 13:11:50 +0300 Subject: [PATCH 073/303] Lincense header fix --- .../java/org/thingsboard/server/controller/BaseController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 65d3fd25a8..19e924a6a4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -5,7 +5,7 @@ * 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 + * 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, From 5e2e7e573d8ed0977f53601cfe333ee53308cb46 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 15 Oct 2021 15:10:13 +0300 Subject: [PATCH 074/303] DelayNode: nodeDetails changed --- .../org/thingsboard/rule/engine/delay/TbMsgDelayNode.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index 17cdae53b8..989a080f88 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -41,7 +41,10 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; name = "delay (deprecated)", configClazz = TbMsgDelayNodeConfiguration.class, nodeDescription = "Delays incoming message (deprecated)", - nodeDetails = "Deprecated! Delays messages for configurable period. Please note, this node acknowledges the message from the current queue (message will be removed from queue)", + nodeDetails = "Delays messages for a configurable period. " + + "Please note, this node acknowledges the message from the current queue (message will be removed from queue). " + + "Deprecated because the acknowledged message still stays in memory (to be delayed) and this " + + "does not guarantee that message will be processed even if the \"retry failures and timeouts\" processing strategy will be chosen.", icon = "pause", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeMsgDelayConfig" From 2c743f647c4a17f95562d5a5a85db778fbaed065 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 15 Oct 2021 14:36:28 +0300 Subject: [PATCH 075/303] SQL_RELATIONS_MAX_LEVEL parameter added --- .../src/main/resources/thingsboard.yml | 2 + .../query/DefaultEntityQueryRepository.java | 14 ++++++- .../DefaultEntityQueryRepositoryTest.java | 42 ++++++++++++------- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 2c8d0c63bc..2b108c2eb9 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -279,6 +279,8 @@ sql: rpc: enabled: "${SQL_TTL_RPC_ENABLED:true}" checking_interval: "${SQL_RPC_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours + relations: + max_level: "${SQL_RELATIONS_MAX_LEVEL:50}" # //This value has to be reasonable small to prevent infinite recursion as early as possible # Actor system parameters actors: diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index f567420947..a838dedd1a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -15,8 +15,10 @@ */ package org.thingsboard.server.dao.sql.query; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.transaction.support.TransactionTemplate; @@ -223,7 +225,6 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private static final String SELECT_API_USAGE_STATE = "(select aus.id, aus.created_time, aus.tenant_id, aus.entity_id, " + "coalesce((select title from tenant where id = aus.entity_id), (select title from customer where id = aus.entity_id)) as name " + "from api_usage_state as aus)"; - static final int MAX_LEVEL_DEFAULT = 50; //This value has to be reasonable small to prevent infinite recursion as early as possible static { entityTableMap.put(EntityType.ASSET, "asset"); @@ -268,6 +269,10 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private static final String HIERARCHICAL_TO_QUERY_TEMPLATE = HIERARCHICAL_QUERY_TEMPLATE.replace("$in", "to").replace("$out", "from"); private static final String HIERARCHICAL_FROM_QUERY_TEMPLATE = HIERARCHICAL_QUERY_TEMPLATE.replace("$in", "from").replace("$out", "to"); + @Getter + @Value("${sql.relations.max_level:50}") + int maxLevelAllowed; //This value has to be reasonable small to prevent infinite recursion as early as possible + private final NamedParameterJdbcTemplate jdbcTemplate; private final TransactionTemplate transactionTemplate; private final DefaultQueryLogComponent queryLog; @@ -711,7 +716,12 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { } int getMaxLevel(int maxLevel) { - return maxLevel > 0 ? maxLevel : MAX_LEVEL_DEFAULT; + int level = maxLevel > 0 ? maxLevel : this.maxLevelAllowed; + if (level > this.maxLevelAllowed) { + log.debug("hierarchy level {} is reduced down to maxLevelAllowed {}", level, this.maxLevelAllowed); + return this.maxLevelAllowed; + } + return level; } private String getQueryTemplate(EntitySearchDirection direction) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepositoryTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepositoryTest.java index a0c716d51f..1a0ce4cebc 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepositoryTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepositoryTest.java @@ -16,42 +16,54 @@ package org.thingsboard.server.dao.sql.query; import org.junit.Test; -import org.thingsboard.server.common.data.id.CustomerId; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.support.TransactionTemplate; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.BDDMockito.willCallRealMethod; -import static org.mockito.Mockito.mock; +@RunWith(SpringRunner.class) +@SpringBootTest(classes = DefaultEntityQueryRepository.class) public class DefaultEntityQueryRepositoryTest { + @MockBean + NamedParameterJdbcTemplate jdbcTemplate; + @MockBean + TransactionTemplate transactionTemplate; + @MockBean + DefaultQueryLogComponent queryLog; + + @Autowired + DefaultEntityQueryRepository repo; + /* * This value has to be reasonable small to prevent infinite recursion as early as possible * */ @Test public void givenDefaultMaxLevel_whenStaticConstant_thenEqualsTo() { - assertThat(DefaultEntityQueryRepository.MAX_LEVEL_DEFAULT, equalTo(10)); + assertThat(repo.getMaxLevelAllowed(), equalTo(50)); } @Test public void givenMaxLevelZeroOrNegative_whenGetMaxLevel_thenReturnDefaultMaxLevel() { - DefaultEntityQueryRepository repo = mock(DefaultEntityQueryRepository.class); - willCallRealMethod().given(repo).getMaxLevel(anyInt()); - assertThat(repo.getMaxLevel(0), equalTo(DefaultEntityQueryRepository.MAX_LEVEL_DEFAULT)); - assertThat(repo.getMaxLevel(-1), equalTo(DefaultEntityQueryRepository.MAX_LEVEL_DEFAULT)); - assertThat(repo.getMaxLevel(-2), equalTo(DefaultEntityQueryRepository.MAX_LEVEL_DEFAULT)); - assertThat(repo.getMaxLevel(Integer.MIN_VALUE), equalTo(DefaultEntityQueryRepository.MAX_LEVEL_DEFAULT)); + assertThat(repo.getMaxLevel(0), equalTo(repo.getMaxLevelAllowed())); + assertThat(repo.getMaxLevel(-1), equalTo(repo.getMaxLevelAllowed())); + assertThat(repo.getMaxLevel(-2), equalTo(repo.getMaxLevelAllowed())); + assertThat(repo.getMaxLevel(Integer.MIN_VALUE), equalTo(repo.getMaxLevelAllowed())); } @Test public void givenMaxLevelPositive_whenGetMaxLevel_thenValueTheSame() { - DefaultEntityQueryRepository repo = mock(DefaultEntityQueryRepository.class); - willCallRealMethod().given(repo).getMaxLevel(anyInt()); assertThat(repo.getMaxLevel(1), equalTo(1)); assertThat(repo.getMaxLevel(2), equalTo(2)); - assertThat(repo.getMaxLevel(Integer.MAX_VALUE), equalTo(Integer.MAX_VALUE)); + assertThat(repo.getMaxLevel(repo.getMaxLevelAllowed()), equalTo(repo.getMaxLevelAllowed())); + assertThat(repo.getMaxLevel(repo.getMaxLevelAllowed() + 1), equalTo(repo.getMaxLevelAllowed())); + assertThat(repo.getMaxLevel(Integer.MAX_VALUE), equalTo(repo.getMaxLevelAllowed())); } } From caddc4d4d76372ecc4a1e6a274f2c6691545308e Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 15 Oct 2021 14:56:06 +0300 Subject: [PATCH 076/303] getMaxLevel has refactored to simplify the code --- .../server/dao/sql/query/DefaultEntityQueryRepository.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index a838dedd1a..ac78e80685 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -716,12 +716,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { } int getMaxLevel(int maxLevel) { - int level = maxLevel > 0 ? maxLevel : this.maxLevelAllowed; - if (level > this.maxLevelAllowed) { - log.debug("hierarchy level {} is reduced down to maxLevelAllowed {}", level, this.maxLevelAllowed); - return this.maxLevelAllowed; - } - return level; + return (maxLevel <= 0 || maxLevel > this.maxLevelAllowed) ? this.maxLevelAllowed : maxLevel; } private String getQueryTemplate(EntitySearchDirection direction) { From 2627fe51d491055d4140f16617ed543f7f5bd8f6 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 15 Oct 2021 15:21:28 +0300 Subject: [PATCH 077/303] AlarmNode: refactored alarm details build js template - moved to abstract class --- .../action/TbAbstractAlarmNodeConfiguration.java | 14 ++++++++++++++ .../action/TbClearAlarmNodeConfiguration.java | 14 +------------- .../action/TbCreateAlarmNodeConfiguration.java | 6 +----- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNodeConfiguration.java index 69ad95cf40..1cd7c64422 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNodeConfiguration.java @@ -20,6 +20,20 @@ import lombok.Data; @Data public abstract class TbAbstractAlarmNodeConfiguration { + static final String ALARM_DETAILS_BUILD_JS_TEMPLATE = "" + + "//***DO NOT CHANGE THIS LINES***\n" + + "var details = {};\n" + + "if (metadata.prevAlarmDetails) {\n" + + " details = JSON.parse(metadata.prevAlarmDetails);\n" + + " //remove prevAlarmDetails from metadata\n" + + " delete metadata.prevAlarmDetails;\n" + + " //now metadata is the same as it comes IN this rule node" + + "}\n" + + "//***PLACE YOUR CODE BELOW***\n" + + "\n" + + "\n" + + "return details;"; + private String alarmType; private String alarmDetailsBuildJs; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNodeConfiguration.java index 24736136f2..df29ad072d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNodeConfiguration.java @@ -25,19 +25,7 @@ public class TbClearAlarmNodeConfiguration extends TbAbstractAlarmNodeConfigurat @Override public TbClearAlarmNodeConfiguration defaultConfiguration() { TbClearAlarmNodeConfiguration configuration = new TbClearAlarmNodeConfiguration(); - configuration.setAlarmDetailsBuildJs("" + - "//***DO NOT CHANGE THIS LINES***\n" + - "var details = {};\n" + - "if (metadata.prevAlarmDetails) {\n" + - " details = JSON.parse(metadata.prevAlarmDetails);\n" + - " //remove prevAlarmDetails from metadata\n" + - " delete metadata.prevAlarmDetails;\n" + - " //now metadata is the same as it comes IN this rule node" + - "}\n" + - "//***PLACE YOUR CODE BELOW***\n" + - "\n" + - "\n" + - "return details;"); + configuration.setAlarmDetailsBuildJs(ALARM_DETAILS_BUILD_JS_TEMPLATE); configuration.setAlarmType("General Alarm"); return configuration; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNodeConfiguration.java index 3173b4ab67..2d03612058 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNodeConfiguration.java @@ -35,11 +35,7 @@ public class TbCreateAlarmNodeConfiguration extends TbAbstractAlarmNodeConfigura @Override public TbCreateAlarmNodeConfiguration defaultConfiguration() { TbCreateAlarmNodeConfiguration configuration = new TbCreateAlarmNodeConfiguration(); - configuration.setAlarmDetailsBuildJs("var details = {};\n" + - "if (metadata.prevAlarmDetails) {\n" + - " details = JSON.parse(metadata.prevAlarmDetails);\n" + - "}\n" + - "return details;"); + configuration.setAlarmDetailsBuildJs(ALARM_DETAILS_BUILD_JS_TEMPLATE); configuration.setAlarmType("General Alarm"); configuration.setSeverity(AlarmSeverity.CRITICAL.name()); configuration.setPropagate(false); From f47de8cfa60220c12f1eef357f132b0e1a8173af Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 15 Oct 2021 16:15:01 +0300 Subject: [PATCH 078/303] Device Profile controller --- .../server/controller/BaseController.java | 8 +- .../server/controller/DeviceController.java | 4 +- .../controller/DeviceProfileController.java | 108 +++++++++++++++--- .../server/common/data/DeviceProfile.java | 43 ++++++- 4 files changed, 140 insertions(+), 23 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index afe21ae0dd..923ae1588c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -165,7 +165,7 @@ public abstract class BaseController { "See the 'Model' tab of the Response Class for more details. "; public static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String DEVICE_PROFILE_ID_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String DEVICE_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String TENANT_ID_PARAM_DESCRIPTION = "A string value representing the tenant id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String EDGE_ID_PARAM_DESCRIPTION = "A string value representing the edge id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; @@ -176,6 +176,8 @@ public abstract class BaseController { public static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority."; + protected static final String TENANT_AND_USER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -186,6 +188,7 @@ public abstract class BaseController { protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; + protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name."; protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name."; protected static final String EVENT_TEXT_SEARCH_DESCRIPTION = "The value is not used in searching."; @@ -194,6 +197,7 @@ public abstract class BaseController { protected static final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title"; protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; + protected static final String DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, transportType, description, isDefault"; protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; @@ -201,11 +205,13 @@ public abstract class BaseController { protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; + protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP"; protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; protected static final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that also contains name of the alarm originator."; protected static final String RELATION_INFO_DESCRIPTION = "Relation Info is an extension of the default Relation object that contains information about the 'from' and 'to' entity names. "; protected static final String EDGE_INFO_DESCRIPTION = "Edge Info is an extension of the default Edge object that contains information about the assigned customer name. "; + protected static final String DEVICE_PROFILE_INFO_DESCRIPTION = "Device Profile Info is a lightweight object that includes main information about Device Profile excluding the heavyweight configuration object. "; protected static final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; protected static final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; 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 ed88cbc78b..6fa7f8755a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -415,7 +415,7 @@ public class DeviceController extends BaseController { @RequestParam int page, @ApiParam(value = DEVICE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, - @ApiParam(value = DEVICE_PROFILE_ID_DESCRIPTION) + @ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) @RequestParam(required = false) String deviceProfileId, @ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, @@ -509,7 +509,7 @@ public class DeviceController extends BaseController { @RequestParam int page, @ApiParam(value = DEVICE_TYPE_DESCRIPTION) @RequestParam(required = false) String type, - @ApiParam(value = DEVICE_PROFILE_ID_DESCRIPTION) + @ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) @RequestParam(required = false) String deviceProfileId, @ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 3a68551773..cae479814d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -58,10 +60,16 @@ public class DeviceProfileController extends BaseController { @Autowired private TimeseriesService timeseriesService; + @ApiOperation(value = "Get Device Profile (getDeviceProfileById)", + notes = "Fetch the Device Profile object based on the provided Device Profile Id. " + + "The server checks that the device profile is owned by the same tenant. " + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.GET) @ResponseBody - public DeviceProfile getDeviceProfileById(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { + public DeviceProfile getDeviceProfileById( + @ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); try { DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); @@ -71,10 +79,16 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Get Device Profile Info (getDeviceProfileInfoById)", + notes = "Fetch the Device Profile Info object based on the provided Device Profile Id. " + + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET) @ResponseBody - public DeviceProfileInfo getDeviceProfileInfoById(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { + public DeviceProfileInfo getDeviceProfileInfoById( + @ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); try { DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); @@ -84,6 +98,10 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Get Default Device Profile (getDefaultDeviceProfileInfo)", + notes = "Fetch the Default Device Profile Info object. " + + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET) @ResponseBody @@ -95,10 +113,18 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Get time-series keys (getTimeseriesKeys)", + notes = "Get a set of unique time-series keys used by devices that belong to specified profile. " + + "If profile is not set returns a list of unique keys among all profiles. " + + "The call is used for auto-complete in the UI forms. " + + "The implementation limits the number of devices that participate in search to 100 as a trade of between accurate results and time-consuming queries. " + + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/deviceProfile/devices/keys/timeseries", method = RequestMethod.GET) @ResponseBody public List getTimeseriesKeys( + @ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) @RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException { DeviceProfileId deviceProfileId; if (StringUtils.isNotEmpty(deviceProfileIdStr)) { @@ -115,10 +141,18 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Get attribute keys (getAttributesKeys)", + notes = "Get a set of unique attribute keys used by devices that belong to specified profile. " + + "If profile is not set returns a list of unique keys among all profiles. " + + "The call is used for auto-complete in the UI forms. " + + "The implementation limits the number of devices that participate in search to 100 as a trade of between accurate results and time-consuming queries. " + + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/deviceProfile/devices/keys/attributes", method = RequestMethod.GET) @ResponseBody public List getAttributesKeys( + @ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) @RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException { DeviceProfileId deviceProfileId; if (StringUtils.isNotEmpty(deviceProfileIdStr)) { @@ -135,10 +169,20 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Create Or Update Device Profile (saveDevice)", + notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created device profile id will be present in the response. " + + "Specify existing device profile id to update the device profile. " + + "Referencing non-existing device profile Id will cause 'Not Found' error. " + + "\n\nDevice profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json", + consumes = "application/json") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/deviceProfile", method = RequestMethod.POST) @ResponseBody - public DeviceProfile saveDeviceProfile(@RequestBody DeviceProfile deviceProfile) throws ThingsboardException { + public DeviceProfile saveDeviceProfile( + @ApiParam(value = "A JSON value representing the device profile.") + @RequestBody DeviceProfile deviceProfile) throws ThingsboardException { try { boolean created = deviceProfile.getId() == null; deviceProfile.setTenantId(getTenantId()); @@ -180,10 +224,16 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Delete device profile (deleteDeviceProfile)", + notes = "Deletes the device profile. Referencing non-existing device profile Id will cause an error. " + + "Can't delete the device profile if it is referenced by existing devices." + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteDeviceProfile(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { + public void deleteDeviceProfile( + @ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); try { DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); @@ -207,10 +257,15 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Make Device Profile Default (setDefaultDeviceProfile)", + notes = "Marks device profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/deviceProfile/{deviceProfileId}/default", method = RequestMethod.POST) @ResponseBody - public DeviceProfile setDefaultDeviceProfile(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { + public DeviceProfile setDefaultDeviceProfile( + @ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); try { DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); @@ -238,14 +293,24 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Get Device Profiles (getDeviceProfiles)", + notes = "Returns a page of devices profile objects owned by tenant. " + + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/deviceProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public PageData getDeviceProfiles(@RequestParam int pageSize, - @RequestParam int page, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + public PageData getDeviceProfiles( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(deviceProfileService.findDeviceProfiles(getTenantId(), pageLink)); @@ -254,15 +319,26 @@ public class DeviceProfileController extends BaseController { } } + @ApiOperation(value = "Get Device Profiles for transport type (getDeviceProfileInfos)", + notes = "Returns a page of devices profile info objects owned by tenant. " + + PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public PageData getDeviceProfileInfos(@RequestParam int pageSize, - @RequestParam int page, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder, - @RequestParam(required = false) String transportType) throws ThingsboardException { + public PageData getDeviceProfileInfos( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder, + @ApiParam(value = "Type of the transport", allowableValues = TRANSPORT_TYPE_ALLOWABLE_VALUES) + @RequestParam(required = false) String transportType) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(deviceProfileService.findDeviceProfileInfos(getTenantId(), pageLink, transportType)); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 13c4692976..5e0419cf90 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -17,6 +17,8 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -34,34 +36,51 @@ import java.io.IOException; import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.mapper; +@ApiModel @Data @EqualsAndHashCode(callSuper = true) @Slf4j public class DeviceProfile extends SearchTextBased implements HasName, HasTenantId, HasOtaPackage { + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id that owns the profile.", readOnly = true) private TenantId tenantId; @NoXss + @ApiModelProperty(position = 4, value = "Unique Device Profile Name in scope of Tenant.", example = "Moisture Sensor") private String name; @NoXss + @ApiModelProperty(position = 11, value = "Device Profile description. ") private String description; + @ApiModelProperty(position = 12, value = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ") private String image; private boolean isDefault; + @ApiModelProperty(position = 16, value = "Type of the profile. Always 'DEFAULT' for now. Reserved for future use.") private DeviceProfileType type; + @ApiModelProperty(position = 14, value = "Type of the transport used to connect the device. Default transport supports HTTP, CoAP and MQTT.") private DeviceTransportType transportType; + @ApiModelProperty(position = 15, value = "Provisioning strategy.") private DeviceProfileProvisionType provisionType; + @ApiModelProperty(position = 7, value = "Reference to the rule chain. " + + "If present, the specified rule chain will be used to process all messages related to device, including telemetry, attribute updates, etc. " + + "Otherwise, the root rule chain will be used to process those messages.") private RuleChainId defaultRuleChainId; + @ApiModelProperty(position = 6, value = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.") private DashboardId defaultDashboardId; @NoXss + @ApiModelProperty(position = 8, value = "Reference to the rule engine queue. " + + "If present, the specified queue will be used to store all unprocessed messages related to device, including telemetry, attribute updates, etc. " + + "Otherwise, the 'Main' queue will be used to store those messages.") private String defaultQueueName; @Valid private transient DeviceProfileData profileData; @JsonIgnore private byte[] profileDataBytes; @NoXss + @ApiModelProperty(position = 13, value = "Unique provisioning key used by 'Device Provisioning' feature.") private String provisionDeviceKey; + @ApiModelProperty(position = 9, value = "Reference to the firmware OTA package. If present, the specified package will be used as default device firmware. ") private OtaPackageId firmwareId; - + @ApiModelProperty(position = 10, value = "Reference to the software OTA package. If present, the specified package will be used as default device software. ") private OtaPackageId softwareId; public DeviceProfile() { @@ -88,16 +107,32 @@ public class DeviceProfile extends SearchTextBased implements H this.softwareId = deviceProfile.getSoftwareId(); } + @ApiModelProperty(position = 1, value = "JSON object with the device profile Id. " + + "Specify this field to update the device profile. " + + "Referencing non-existing device profile Id will cause error. " + + "Omit this field to create new device profile.") + @Override + public DeviceProfileId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the profile creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + @Override public String getSearchText() { return getName(); } - @Override - public String getName() { - return name; + @ApiModelProperty(position = 5, value = "Used to mark the default profile. Default profile is used when the device profile is not specified during device creation.") + public boolean isDefault(){ + return isDefault; } + @ApiModelProperty(position = 16, value = "Complex JSON object that includes addition device profile configuration (transport, alarm rules, etc).") public DeviceProfileData getProfileData() { if (profileData != null) { return profileData; From d7c09b9f6721d4b0f713a57058f0b5c8712aabb9 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 15 Oct 2021 15:08:40 +0300 Subject: [PATCH 079/303] Added Api swagger desc for assing*ToEdge and unassing*FromEdge --- .../server/controller/AssetController.java | 14 +++++++++++--- .../server/controller/BaseController.java | 5 +++++ .../server/controller/DashboardController.java | 14 ++++++++++++++ .../server/controller/DeviceController.java | 15 ++++++++++++--- .../server/controller/EdgeController.java | 2 +- .../server/controller/EntityViewController.java | 16 ++++++++++++++++ .../server/controller/RuleChainController.java | 17 +++++++++++++++++ .../server/dao/rule/BaseRuleChainService.java | 3 +++ 8 files changed, 79 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index 94c741c774..e7fff3584c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -518,8 +518,11 @@ public class AssetController extends BaseController { @ApiOperation(value = "Assign asset to edge (assignAssetToEdge)", notes = "Creates assignment of an existing asset to an instance of The Edge. " + - "The Edge is a software product for edge computing. " + - "It allows bringing data analysis and management to the edge, while seamlessly synchronizing with the platform server (cloud). ", produces = MediaType.APPLICATION_JSON_VALUE) + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive a copy of assignment asset " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once asset will be delivered to edge service, it's going to be available for usage on remote edge instance.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST) @ResponseBody @@ -554,7 +557,12 @@ public class AssetController extends BaseController { } @ApiOperation(value = "Unassign asset from edge (unassignAssetFromEdge)", - notes = "Clears assignment of the asset to the edge", produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Clears assignment of the asset to the edge. " + + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive an 'unassign' command to remove asset " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once 'unassign' command will be delivered to edge service, it's going to remove asset locally.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.DELETE) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 923ae1588c..4ec52d5891 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -219,6 +219,11 @@ public abstract class BaseController { protected static final String EVENT_START_TIME_DESCRIPTION = "Timestamp. Events with creation time before it won't be queried."; protected static final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; + protected static final String EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Unassignment works in async way - first, 'unassign' notification event pushed to edge queue on platform. "; + protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)" ; + protected static final String EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Assignment works in async way - first, notification event pushed to edge service queue on platform. "; + protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; + protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n"; protected static final String MARKDOWN_CODE_BLOCK_END = "\n```"; protected static final String EVENT_ERROR_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"ERROR\", \"server\": \"ip-172-31-24-152\", " + diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 3f87a321d8..c84b4d0eaa 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -805,6 +805,13 @@ public class DashboardController extends BaseController { return null; } + @ApiOperation(value = "Assign dashboard to edge (assignDashboardToEdge)", + notes = "Creates assignment of an existing dashboard to an instance of The Edge. " + + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive a copy of assignment dashboard " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once dashboard will be delivered to edge service, it's going to be available for usage on remote edge instance.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.POST) @ResponseBody @@ -838,6 +845,13 @@ public class DashboardController extends BaseController { } } + @ApiOperation(value = "Unassign dashboard from edge (unassignDashboardFromEdge)", + notes = "Clears assignment of the dashboard to the edge. " + + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive an 'unassign' command to remove dashboard " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once 'unassign' command will be delivered to edge service, it's going to remove dashboard locally.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.DELETE) @ResponseBody 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 6fa7f8755a..a1e4a87b07 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -24,6 +24,7 @@ import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -782,8 +783,11 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Assign device to edge (assignDeviceToEdge)", notes = "Creates assignment of an existing device to an instance of The Edge. " + - "The Edge is a software product for edge computing. " + - "It allows bringing data analysis and management to the edge, while seamlessly synchronizing with the platform server (cloud). ") + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive a copy of assignment device " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once device will be delivered to edge service, it's going to be available for usage on remote edge instance.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.POST) @ResponseBody @@ -821,7 +825,12 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Unassign device from edge (unassignDeviceFromEdge)", - notes = "Clears assignment of the device to the edge") + notes = "Clears assignment of the device to the edge. " + + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive an 'unassign' command to remove device " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once 'unassign' command will be delivered to edge service, it's going to remove device locally.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.DELETE) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 4c8e21de99..caec5f325b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -142,7 +142,7 @@ public class EdgeController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge", method = RequestMethod.POST) @ResponseBody - public Edge saveEdge(@ApiParam(value = "A JSON value representing the ed.", required = true) + public Edge saveEdge(@ApiParam(value = "A JSON value representing the edge.", required = true) @RequestBody Edge edge) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java index 6802130338..b323286b7c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -20,9 +20,11 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; +import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -611,6 +613,13 @@ public class EntityViewController extends BaseController { } } + @ApiOperation(value = "Assign entity view to edge (assignEntityViewToEdge)", + notes = "Creates assignment of an existing entity view to an instance of The Edge. " + + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive a copy of assignment entity view " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once entity view will be delivered to edge service, it's going to be available for usage on remote edge instance.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.POST) @ResponseBody @@ -641,6 +650,13 @@ public class EntityViewController extends BaseController { } } + @ApiOperation(value = "Unassign entity view from edge (unassignEntityViewFromEdge)", + notes = "Clears assignment of the entity view to the edge. " + + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive an 'unassign' command to remove entity view " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once 'unassign' command will be delivered to edge service, it's going to remove entity view locally.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.DELETE) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index a71fb70e0a..40cc46ffa1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -20,10 +20,12 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -494,6 +496,14 @@ public class RuleChainController extends BaseController { return msgData; } + @ApiOperation(value = "Assign rule chain to edge (assignRuleChainToEdge)", + notes = "Creates assignment of an existing rule chain to an instance of The Edge. " + + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive a copy of assignment rule chain " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once rule chain will be delivered to edge service, it's going to start processing messages locally. " + + "\n\nOnly rule chain with type 'EDGE' can be assigned to edge.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.POST) @ResponseBody @@ -527,6 +537,13 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Unassign rule chain from edge (unassignRuleChainFromEdge)", + notes = "Clears assignment of the rule chain to the edge. " + + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + + "Second, remote edge service will receive an 'unassign' command to remove rule chain " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + "Third, once 'unassign' command will be delivered to edge service, it's going to remove rule chain locally.", + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.DELETE) @ResponseBody diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 2ead3f4334..f84c0b7516 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -544,6 +544,9 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (!edge.getTenantId().equals(ruleChain.getTenantId())) { throw new DataValidationException("Can't assign ruleChain to edge from different tenant!"); } + if (!RuleChainType.EDGE.equals(ruleChain.getType())) { + throw new DataValidationException("Can't assign non EDGE ruleChain to edge!"); + } try { createRelation(tenantId, new EntityRelation(edgeId, ruleChainId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); } catch (Exception e) { From 1f94ff97327e3afb3aac3da32bd9f3ac4a3b1ea8 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Sun, 17 Oct 2021 21:39:04 +0300 Subject: [PATCH 080/303] Swagger docs for OAuth2Controller and OAuth2ConfigTemplateController --- .../OAuth2ConfigTemplateController.java | 24 +++++++++++++++---- .../server/controller/OAuth2Controller.java | 19 +++++++++++++++ .../data/oauth2/OAuth2BasicMapperConfig.java | 19 ++++++++++++++- .../common/data/oauth2/OAuth2ClientInfo.java | 10 +++++++- .../OAuth2ClientRegistrationTemplate.java | 16 +++++++++++++ .../common/data/oauth2/OAuth2DomainInfo.java | 5 ++++ .../server/common/data/oauth2/OAuth2Info.java | 12 +++++++++- .../data/oauth2/OAuth2MapperConfig.java | 6 +++++ .../common/data/oauth2/OAuth2MobileInfo.java | 5 ++++ .../common/data/oauth2/OAuth2ParamsInfo.java | 8 +++++++ .../data/oauth2/OAuth2RegistrationInfo.java | 24 ++++++++++++++++++- .../server/dao/oauth2/OAuth2ServiceImpl.java | 3 ++- 12 files changed, 142 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java index 434aaf719f..9b9cadfd6c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java +++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java @@ -15,12 +15,18 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.audit.ActionType; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationTemplateId; import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate; @@ -37,6 +43,10 @@ import java.util.List; public class OAuth2ConfigTemplateController extends BaseController { private static final String CLIENT_REGISTRATION_TEMPLATE_ID = "clientRegistrationTemplateId"; + private static final String OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION = "Client registration template is OAuth2 provider configuration template with default settings for registering new OAuth2 clients"; + + @ApiOperation(value = "Create or update OAuth2 client registration template (saveClientRegistrationTemplate)", + notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @@ -49,10 +59,13 @@ public class OAuth2ConfigTemplateController extends BaseController { } } + @ApiOperation(value = "Delete OAuth2 client registration template by id (deleteClientRegistrationTemplate)", + notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/{clientRegistrationTemplateId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteClientRegistrationTemplate(@PathVariable(CLIENT_REGISTRATION_TEMPLATE_ID) String strClientRegistrationTemplateId) throws ThingsboardException { + public void deleteClientRegistrationTemplate(@ApiParam(value = "String representation of client registration template id to delete", example = "139b1f81-2f5d-11ec-9dbe-9b627e1a88f4") + @PathVariable(CLIENT_REGISTRATION_TEMPLATE_ID) String strClientRegistrationTemplateId) throws ThingsboardException { checkParameter(CLIENT_REGISTRATION_TEMPLATE_ID, strClientRegistrationTemplateId); try { accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.DELETE); @@ -63,6 +76,8 @@ public class OAuth2ConfigTemplateController extends BaseController { } } + @ApiOperation(value = "Get the list of all OAuth2 client registration templates (getClientRegistrationTemplates)", + notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(method = RequestMethod.GET, produces = "application/json") @ResponseBody @@ -74,4 +89,5 @@ public class OAuth2ConfigTemplateController extends BaseController { throw handleException(e); } } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java index 7497e20122..bfa29d0ceb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -50,10 +52,20 @@ public class OAuth2Controller extends BaseController { @Autowired private OAuth2Configuration oAuth2Configuration; + + @ApiOperation(value = "Get OAuth2 clients (getOAuth2Clients)", notes = "Get the list of OAuth2 clients " + + "to log in with, available for such domain scheme (HTTP or HTTPS) (if x-forwarded-proto request header is present - " + + "the scheme is known from it) and domain name and port (port may be known from x-forwarded-port header)") @RequestMapping(value = "/noauth/oauth2Clients", method = RequestMethod.POST) @ResponseBody public List getOAuth2Clients(HttpServletRequest request, + @ApiParam(value = "Mobile application package name, to find OAuth2 clients " + + "where there is configured mobile application with such package name") @RequestParam(required = false) String pkgName, + @ApiParam(value = "Platform type to search OAuth2 clients for which " + + "the usage with this platform type is allowed in the settings. " + + "If platform type is not one of allowable values - it will just be ignored", + allowableValues = "WEB, ANDROID, IOS") @RequestParam(required = false) String platform) throws ThingsboardException { try { if (log.isDebugEnabled()) { @@ -76,6 +88,7 @@ public class OAuth2Controller extends BaseController { } } + @ApiOperation(value = "Get current OAuth2 settings (getCurrentOAuth2Info)") @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/oauth2/config", method = RequestMethod.GET, produces = "application/json") @ResponseBody @@ -88,6 +101,7 @@ public class OAuth2Controller extends BaseController { } } + @ApiOperation(value = "Save OAuth2 settings (saveOAuth2Info)") @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/oauth2/config", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @@ -101,6 +115,10 @@ public class OAuth2Controller extends BaseController { } } + @ApiOperation(value = "Get OAuth2 log in processing URL (getLoginProcessingUrl)", notes = "Returns the URL enclosed in " + + "double quotes. After successful authentication with OAuth2 provider, it makes a redirect to this path so that the platform can do " + + "further log in processing. This URL may be configured as 'security.oauth2.loginProcessingUrl' property in yml configuration file, or " + + "as 'SECURITY_OAUTH2_LOGIN_PROCESSING_URL' env variable. By default it is '/login/oauth2/code/'") @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/oauth2/loginProcessingUrl", method = RequestMethod.GET) @ResponseBody @@ -112,4 +130,5 @@ public class OAuth2Controller extends BaseController { throw handleException(e); } } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2BasicMapperConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2BasicMapperConfig.java index 9e90ce14eb..652929bc96 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2BasicMapperConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2BasicMapperConfig.java @@ -15,19 +15,36 @@ */ package org.thingsboard.server.common.data.oauth2; -import lombok.*; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; @Builder(toBuilder = true) @EqualsAndHashCode @Data @ToString +@ApiModel public class OAuth2BasicMapperConfig { + @ApiModelProperty(value = "Email attribute key of OAuth2 principal attributes. " + + "Must be specified for BASIC mapper type and cannot be specified for GITHUB type") private final String emailAttributeKey; + @ApiModelProperty(value = "First name attribute key") private final String firstNameAttributeKey; + @ApiModelProperty(value = "Last name attribute key") private final String lastNameAttributeKey; + @ApiModelProperty(value = "Tenant naming strategy. For DOMAIN type, domain for tenant name will be taken from the email (substring before '@')", required = true) private final TenantNameStrategyType tenantNameStrategy; + @ApiModelProperty(value = "Tenant name pattern for CUSTOM naming strategy. " + + "OAuth2 attributes in the pattern can be used by enclosing attribute key in '%{' and '}'", example = "%{email}") private final String tenantNamePattern; + @ApiModelProperty(value = "Customer name pattern. When creating a user on the first OAuth2 log in, if specified, " + + "customer name will be used to create or find existing customer in the platform and assign customerId to the user") private final String customerNamePattern; + @ApiModelProperty(value = "Name of the tenant's dashboard to set as default dashboard for newly created user") private final String defaultDashboardName; + @ApiModelProperty(value = "Whether default dashboard should be open in full screen") private final boolean alwaysFullScreen; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientInfo.java index cf9478a33a..8e7d891eb9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientInfo.java @@ -15,19 +15,26 @@ */ package org.thingsboard.server.common.data.oauth2; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; @EqualsAndHashCode @Data @NoArgsConstructor @AllArgsConstructor +@ApiModel public class OAuth2ClientInfo { + @ApiModelProperty(value = "OAuth2 client name", example = "GitHub") private String name; + @ApiModelProperty(value = "Name of the icon, displayed on OAuth2 log in button", example = "github-logo") private String icon; + @ApiModelProperty(value = "URI for OAuth2 log in. On HTTP GET request to this URI, it redirects to the OAuth2 provider page", + example = "/oauth2/authorization/8352f191-2b4d-11ec-9ed1-cbf57c026ecc") private String url; public OAuth2ClientInfo(OAuth2ClientInfo oauth2ClientInfo) { @@ -35,4 +42,5 @@ public class OAuth2ClientInfo { this.icon = oauth2ClientInfo.getIcon(); this.url = oauth2ClientInfo.getUrl(); } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java index b46f23484f..56f866eaab 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.oauth2; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -29,20 +31,34 @@ import java.util.List; @Data @ToString @NoArgsConstructor +@ApiModel public class OAuth2ClientRegistrationTemplate extends SearchTextBasedWithAdditionalInfo implements HasName { + @ApiModelProperty(value = "OAuth2 provider identifier (e.g. its name)", required = true) private String providerId; + @ApiModelProperty(value = "Default config for mapping OAuth2 log in response to platform entities") private OAuth2MapperConfig mapperConfig; + @ApiModelProperty(value = "Default authorization URI of the OAuth2 provider") private String authorizationUri; + @ApiModelProperty(value = "Default access token URI of the OAuth2 provider") private String accessTokenUri; + @ApiModelProperty(value = "Default OAuth scopes that will be requested from OAuth2 platform") private List scope; + @ApiModelProperty(value = "Default user info URI of the OAuth2 provider") private String userInfoUri; + @ApiModelProperty(value = "Default name of the username attribute in OAuth2 provider log in response") private String userNameAttributeName; + @ApiModelProperty(value = "Default JSON Web Key URI of the OAuth2 provider") private String jwkSetUri; + @ApiModelProperty(value = "Default client authentication method to use: 'BASIC' or 'POST'") private String clientAuthenticationMethod; + @ApiModelProperty(value = "Comment for OAuth2 provider") private String comment; + @ApiModelProperty(value = "Default log in button icon for OAuth2 provider") private String loginButtonIcon; + @ApiModelProperty(value = "Default OAuth2 provider label") private String loginButtonLabel; + @ApiModelProperty(value = "Help link for OAuth2 provider") private String helpLink; public OAuth2ClientRegistrationTemplate(OAuth2ClientRegistrationTemplate clientRegistrationTemplate) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2DomainInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2DomainInfo.java index 9d9bd939da..d4182a3dba 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2DomainInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2DomainInfo.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.oauth2; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -28,7 +30,10 @@ import lombok.ToString; @NoArgsConstructor @AllArgsConstructor @Builder +@ApiModel public class OAuth2DomainInfo { + @ApiModelProperty(value = "Domain scheme. Mixed scheme means than both HTTP and HTTPS are going to be used", required = true) private SchemeType scheme; + @ApiModelProperty(value = "Domain name. Cannot be empty", required = true) private String name; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java index 72f4b06161..11c241e033 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java @@ -15,7 +15,14 @@ */ package org.thingsboard.server.common.data.oauth2; -import lombok.*; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; import java.util.List; @@ -25,7 +32,10 @@ import java.util.List; @Builder(toBuilder = true) @NoArgsConstructor @AllArgsConstructor +@ApiModel public class OAuth2Info { + @ApiModelProperty("Whether OAuth2 settings are enabled or not") private boolean enabled; + @ApiModelProperty(value = "List of configured OAuth2 clients. Cannot contain null values", required = true) private List oauth2ParamsInfos; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java index 1c4454150f..df0cc45d7b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.oauth2; +import io.swagger.annotations.ApiModelProperty; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; @@ -25,9 +26,14 @@ import lombok.ToString; @Data @ToString public class OAuth2MapperConfig { + @ApiModelProperty(value = "Whether user should be created if not yet present on the platform after successful authentication") private boolean allowUserCreation; + @ApiModelProperty(value = "Whether user credentials should be activated when user is created after successful authentication") private boolean activateUser; + @ApiModelProperty(value = "Type of OAuth2 mapper. Depending on this param, different mapper config fields must be specified", required = true) private MapperType type; + @ApiModelProperty(value = "Mapper config for BASIC and GITHUB mapper types") private OAuth2BasicMapperConfig basic; + @ApiModelProperty(value = "Mapper config for CUSTOM mapper type") private OAuth2CustomMapperConfig custom; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MobileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MobileInfo.java index c04a1a9fd1..5fe3bf5543 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MobileInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MobileInfo.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.oauth2; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -28,7 +30,10 @@ import lombok.ToString; @NoArgsConstructor @AllArgsConstructor @Builder +@ApiModel public class OAuth2MobileInfo { + @ApiModelProperty(value = "Application package name. Cannot be empty", required = true) private String pkgName; + @ApiModelProperty(value = "Application secret. The length must be at least 16 characters", required = true) private String appSecret; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ParamsInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ParamsInfo.java index 1a1d729d6b..f564291679 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ParamsInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ParamsInfo.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.oauth2; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -30,10 +32,16 @@ import java.util.List; @Builder(toBuilder = true) @NoArgsConstructor @AllArgsConstructor +@ApiModel public class OAuth2ParamsInfo { + @ApiModelProperty(value = "List of configured domains where OAuth2 platform will redirect a user after successful " + + "authentication. Cannot be empty. There have to be only one domain with specific name with scheme type 'MIXED'. " + + "Configured domains with the same name must have different scheme types", required = true) private List domainInfos; + @ApiModelProperty(value = "Mobile applications settings. Application package name must be unique within the list", required = true) private List mobileInfos; + @ApiModelProperty(value = "List of OAuth2 provider settings. Cannot be empty", required = true) private List clientRegistrations; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2RegistrationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2RegistrationInfo.java index 3c9a1c1974..f40ca51d14 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2RegistrationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2RegistrationInfo.java @@ -16,7 +16,14 @@ package org.thingsboard.server.common.data.oauth2; import com.fasterxml.jackson.databind.JsonNode; -import lombok.*; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; import java.util.List; @@ -26,19 +33,34 @@ import java.util.List; @NoArgsConstructor @AllArgsConstructor @Builder +@ApiModel public class OAuth2RegistrationInfo { + @ApiModelProperty(value = "Config for mapping OAuth2 log in response to platform entities", required = true) private OAuth2MapperConfig mapperConfig; + @ApiModelProperty(value = "OAuth2 client ID. Cannot be empty", required = true) private String clientId; + @ApiModelProperty(value = "OAuth2 client secret. Cannot be empty", required = true) private String clientSecret; + @ApiModelProperty(value = "Authorization URI of the OAuth2 provider. Cannot be empty", required = true) private String authorizationUri; + @ApiModelProperty(value = "Access token URI of the OAuth2 provider. Cannot be empty", required = true) private String accessTokenUri; + @ApiModelProperty(value = "OAuth scopes that will be requested from OAuth2 platform. Cannot be empty", required = true) private List scope; + @ApiModelProperty(value = "User info URI of the OAuth2 provider") private String userInfoUri; + @ApiModelProperty(value = "Name of the username attribute in OAuth2 provider response. Cannot be empty") private String userNameAttributeName; + @ApiModelProperty(value = "JSON Web Key URI of the OAuth2 provider") private String jwkSetUri; + @ApiModelProperty(value = "Client authentication method to use: 'BASIC' or 'POST'. Cannot be empty", required = true) private String clientAuthenticationMethod; + @ApiModelProperty(value = "OAuth2 provider label. Cannot be empty", required = true) private String loginButtonLabel; + @ApiModelProperty(value = "Log in button icon for OAuth2 provider") private String loginButtonIcon; + @ApiModelProperty(value = "List of platforms for which usage of the OAuth2 client is allowed (empty for all allowed)") private List platforms; + @ApiModelProperty(value = "Additional info of OAuth2 client (e.g. providerName)", required = true) private JsonNode additionalInfo; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java index 3cb0445d78..9411f3be27 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.oauth2; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @@ -224,7 +225,7 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se if (StringUtils.isEmpty(clientRegistration.getAccessTokenUri())) { throw new DataValidationException("Token uri should be specified!"); } - if (StringUtils.isEmpty(clientRegistration.getScope())) { + if (CollectionUtils.isEmpty(clientRegistration.getScope())) { throw new DataValidationException("Scope should be specified!"); } if (StringUtils.isEmpty(clientRegistration.getUserNameAttributeName())) { From 9a383778fc0efdad017c20f3fa032b832c894635 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 18 Oct 2021 12:58:26 +0300 Subject: [PATCH 081/303] Entity Query Controller --- .../server/controller/DeviceController.java | 4 +- .../controller/EntityQueryController.java | 664 +++++++++++++++++- .../common/data/query/EntityCountQuery.java | 2 + .../server/common/data/query/EntityKey.java | 2 + .../server/common/data/query/KeyFilter.java | 2 + 5 files changed, 667 insertions(+), 7 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 a1e4a87b07..87e5dc1142 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -573,7 +573,9 @@ public class DeviceController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/devices", method = RequestMethod.POST) @ResponseBody - public List findByQuery(@RequestBody DeviceSearchQuery query) throws ThingsboardException { + public List findByQuery( + @ApiParam(value = "The device search query JSON") + @RequestBody DeviceSearchQuery query) throws ThingsboardException { checkNotNull(query); checkNotNull(query.getParameters()); checkNotNull(query.getDeviceTypes()); diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 673ac9646b..7a9e3cf23c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -42,15 +44,651 @@ import org.thingsboard.server.service.query.EntityQueryService; @RequestMapping("/api") public class EntityQueryController extends BaseController { + private static final String SINGLE_ENTITY = "\n\n## Single Entity\n\n" + + "Allows to filter only one entity based on the id. For example, this entity filter selects certain device:\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"singleEntity\",\n" + + " \"singleEntity\": {\n" + + " \"id\": \"d521edb0-2a7a-11ec-94eb-213c95f54092\",\n" + + " \"entityType\": \"DEVICE\"\n" + + " }\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String ENTITY_LIST = "\n\n## Entity List Filter\n\n" + + "Allows to filter entities of the same type using their ids. For example, this entity filter selects two devices:\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityList\",\n" + + " \"entityType\": \"DEVICE\",\n" + + " \"entityList\": [\n" + + " \"e6501f30-2a7a-11ec-94eb-213c95f54092\",\n" + + " \"e6657bf0-2a7a-11ec-94eb-213c95f54092\"\n" + + " ]\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String ENTITY_NAME = "\n\n## Entity Name Filter\n\n" + + "Allows to filter entities of the same type using the **'starts with'** expression over entity name. " + + "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityName\",\n" + + " \"entityType\": \"DEVICE\",\n" + + " \"entityNameFilter\": \"Air Quality\"\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String ENTITY_TYPE = "\n\n## Entity Type Filter\n\n" + + "Allows to filter entities based on their type (CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, etc)" + + "For example, this entity filter selects all tenant customers:\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityType\",\n" + + " \"entityType\": \"CUSTOMER\"\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String ASSET_TYPE = "\n\n## Asset Type Filter\n\n" + + "Allows to filter assets based on their type and the **'starts with'** expression over their name. " + + "For example, this entity filter selects all 'charging station' assets which name starts with 'Tesla':\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"assetType\",\n" + + " \"assetType\": \"charging station\",\n" + + " \"assetNameFilter\": \"Tesla\"\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String DEVICE_TYPE = "\n\n## Device Type Filter\n\n" + + "Allows to filter devices based on their type and the **'starts with'** expression over their name. " + + "For example, this entity filter selects all 'Temperature Sensor' devices which name starts with 'ABC':\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"deviceType\",\n" + + " \"deviceType\": \"Temperature Sensor\",\n" + + " \"deviceNameFilter\": \"ABC\"\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String EDGE_TYPE = "\n\n## Edge Type Filter\n\n" + + "Allows to filter edge instances based on their type and the **'starts with'** expression over their name. " + + "For example, this entity filter selects all 'Factory' edge instances which name starts with 'Nevada':\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"edgeType\",\n" + + " \"edgeType\": \"Factory\",\n" + + " \"edgeNameFilter\": \"Nevada\"\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String ENTITY_VIEW_TYPE = "\n\n## Entity View Filter\n\n" + + "Allows to filter entity views based on their type and the **'starts with'** expression over their name. " + + "For example, this entity filter selects all 'Concrete Mixer' entity views which name starts with 'CAT':\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityViewType\",\n" + + " \"entityViewType\": \"Concrete Mixer\",\n" + + " \"entityViewNameFilter\": \"CAT\"\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String API_USAGE = "\n\n## Api Usage Filter\n\n" + + "Allows to query for Api Usage based on optional customer id. If the customer id is not set, returns current tenant API usage." + + "For example, this entity filter selects the 'Api Usage' entity for customer with id 'e6501f30-2a7a-11ec-94eb-213c95f54092':\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"apiUsageState\",\n" + + " \"customerId\": {\n" + + " \"id\": \"d521edb0-2a7a-11ec-94eb-213c95f54092\",\n" + + " \"entityType\": \"CUSTOMER\"\n" + + " }\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String MAX_LEVEL_DESCRIPTION = "Possible direction values are 'TO' and 'FROM'. The 'maxLevel' defines how many relation levels should the query search 'recursively'. "; + private static final String FETCH_LAST_LEVEL_ONLY_DESCRIPTION = "Assuming the 'maxLevel' is > 1, the 'fetchLastLevelOnly' defines either to return all related entities or only entities that are on the last level of relations. "; + + private static final String RELATIONS_QUERY_FILTER = "\n\n## Relations Query Filter\n\n" + + "Allows to filter entities that are related to the provided root entity. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'filter' object allows you to define the relation type and set of acceptable entity types to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only those who match the 'filters'.\n\n" + + "For example, this entity filter selects all devices and assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092':\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"relationsQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e51de0c0-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 1,\n" + + " \"fetchLastLevelOnly\": false,\n" + + " \"filters\": [\n" + + " {\n" + + " \"relationType\": \"Contains\",\n" + + " \"entityTypes\": [\n" + + " \"DEVICE\",\n" + + " \"ASSET\"\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + + private static final String ASSET_QUERY_FILTER = "\n\n## Asset Search Query\n\n" + + "Allows to filter assets that are related to the provided root entity. Filters related assets based on the relation type and set of asset types. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'relationType' defines the type of the relation to search for. " + + "The 'assetTypes' defines the type of the asset to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only assets that match 'relationType' and 'assetTypes' conditions.\n\n" + + "For example, this entity filter selects 'charging station' assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"assetSearchQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e51de0c0-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 1,\n" + + " \"fetchLastLevelOnly\": false,\n" + + " \"relationType\": \"Contains\",\n" + + " \"assetTypes\": [\n" + + " \"charging station\"\n" + + " ]\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String DEVICE_QUERY_FILTER = "\n\n## Device Search Query\n\n" + + "Allows to filter devices that are related to the provided root entity. Filters related devices based on the relation type and set of device types. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'relationType' defines the type of the relation to search for. " + + "The 'deviceTypes' defines the type of the device to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + + "For example, this entity filter selects 'Charging port' and 'Air Quality Sensor' devices which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"deviceSearchQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 2,\n" + + " \"fetchLastLevelOnly\": true,\n" + + " \"relationType\": \"Contains\",\n" + + " \"deviceTypes\": [\n" + + " \"Air Quality Sensor\",\n" + + " \"Charging port\"\n" + + " ]\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String EV_QUERY_FILTER = "\n\n## Entity View Query\n\n" + + "Allows to filter entity views that are related to the provided root entity. Filters related entity views based on the relation type and set of entity view types. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'relationType' defines the type of the relation to search for. " + + "The 'entityViewTypes' defines the type of the entity view to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + + "For example, this entity filter selects 'Concrete mixer' entity views which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityViewSearchQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 1,\n" + + " \"fetchLastLevelOnly\": false,\n" + + " \"relationType\": \"Contains\",\n" + + " \"entityViewTypes\": [\n" + + " \"Concrete mixer\"\n" + + " ]\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String EDGE_QUERY_FILTER = "\n\n## Edge Search Query\n\n" + + "Allows to filter edge instances that are related to the provided root entity. Filters related edge instances based on the relation type and set of edge types. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'relationType' defines the type of the relation to search for. " + + "The 'deviceTypes' defines the type of the device to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + + "For example, this entity filter selects 'Factory' edge instances which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"deviceSearchQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 2,\n" + + " \"fetchLastLevelOnly\": true,\n" + + " \"relationType\": \"Contains\",\n" + + " \"edgeTypes\": [\n" + + " \"Factory\"\n" + + " ]\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String EMPTY = "\n\n## Entity Type Filter\n\n" + + "Allows to filter multiple entities of the same type using the **'starts with'** expression over entity name. " + + "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n"+ + MARKDOWN_CODE_BLOCK_START + + ""+ + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String ENTITY_FILTERS = + "\n\n # Entity Filters" + + "\nEntity Filter body depends on the 'type' parameter. Let's review available entity filter types. In fact, they do correspond to available dashboard aliases." + + SINGLE_ENTITY + ENTITY_LIST + ENTITY_NAME + ENTITY_TYPE + ASSET_TYPE + DEVICE_TYPE + EDGE_TYPE + ENTITY_VIEW_TYPE + API_USAGE + RELATIONS_QUERY_FILTER + + ASSET_QUERY_FILTER + DEVICE_QUERY_FILTER + EV_QUERY_FILTER + EDGE_QUERY_FILTER; + + private static final String FILTER_KEY = "\n\n## Filter Key\n\n" + + "Filter Key defines either entity field, attribute or telemetry. It is a JSON object that consists the key name and type. " + + "The following filter key types are supported: \n\n"+ + " * 'CLIENT_ATTRIBUTE' - used for client attributes; \n" + + " * 'SHARED_ATTRIBUTE' - used for shared attributes; \n" + + " * 'SERVER_ATTRIBUTE' - used for server attributes; \n" + + " * 'ATTRIBUTE' - used for any of the above; \n" + + " * 'TIME_SERIES' - used for time-series values; \n" + + " * 'ENTITY_FIELD' - used for accessing entity fields like 'name', 'label', etc. The list of available fields depends on the entity type; \n" + + " * 'ALARM_FIELD' - similar to entity field, but is used in alarm queries only; \n" + + "\n\n Let's review the example:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + private static final String FILTER_VALUE_TYPE = "\n\n## Value Type and Operations\n\n" + + "Provides a hint about the data type of the entity field that is defined in the filter key. " + + "The value type impacts the list of possible operations that you may use in the corresponding predicate. For example, you may use 'STARTS_WITH' or 'END_WITH', but you can't use 'GREATER_OR_EQUAL' for string values." + + "The following filter value types and corresponding predicate operations are supported: \n\n"+ + " * 'STRING' - used to filter any 'String' or 'JSON' values. Operations: EQUAL, NOT_EQUAL, STARTS_WITH, ENDS_WITH, CONTAINS, NOT_CONTAINS; \n" + + " * 'NUMERIC' - used for 'Long' and 'Double' values. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n" + + " * 'BOOLEAN' - used for boolean values; Operations: EQUAL, NOT_EQUAL \n" + + " * 'DATE_TIME' - similar to numeric, transforms value to milliseconds since epoch. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n"; + + private static final String FILTER_PREDICATE = "\n\n## Filter Predicate\n\n" + + "Filter Predicate defines the logical expression to evaluate. The list of available operations depends on the filter value type, see above. " + + "Platform supports 4 predicate types: 'STRING', 'NUMERIC', 'BOOLEAN' and 'COMPLEX'. The last one allows to combine multiple operations over one filter key." + + "\n\nSimple predicate example to check 'value < 100': \n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 100,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\nComplex predicate example, to check 'value < 10 or value > 20': \n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"OR\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 10,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 20,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\nMore complex predicate example, to check 'value < 10 or (value > 50 && value < 60)': \n\n"+ + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"OR\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 10,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"AND\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 50,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 60,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n YOu may also want to replace hardcoded values (for example, temperature > 20) with the more dynamic " + + "expression (for example, temperature > 'value of the tenant attribute with key 'temperatureThreshold'). " + + "It is possible to use 'dynamicValue' to define attribute of the tenant, customer or user that is performing the API call. " + + "See example below: \n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 0,\n" + + " \"dynamicValue\": {\n" + + " \"sourceType\": \"CURRENT_USER\",\n" + + " \"sourceAttribute\": \"temperatureThreshold\"\n" + + " }\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n Note that you may use 'CURRENT_USER', 'CURRENT_CUSTOMER' and 'CURRENT_TENANT' as a 'sourceType'. The 'defaultValue' is used when the attribute with such a name is not defined for the chosen source."; + + private static final String KEY_FILTERS = + "\n\n # Key Filters" + + "\nKey Filter allows you to define complex logical expressions over entity field, attribute or latest time-series value. The filter is defined using 'key', 'valueType' and 'predicate' objects. " + + "Single Entity Query may have zero, one or multiple predicates. If multiple filters are defined, they are evaluated using logical 'AND'. " + + "The example below checks that temperature of the entity is above 20 degrees:" + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"key\": {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " },\n" + + " \"valueType\": \"NUMERIC\",\n" + + " \"predicate\": {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 20,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n Now let's review 'key', 'valueType' and 'predicate' objects in detail." + + FILTER_KEY + FILTER_VALUE_TYPE + FILTER_PREDICATE; + + private static final String ENTITY_COUNT_QUERY_DESCRIPTION = + "Allows to run complex queries to search the count of platform entities (devices, assets, customers, etc) " + + "based on the combination of main entity filter and multiple key filters. Returns the number of entities that match the query definition.\n\n" + + "# Query Definition\n\n" + + "\n\nMain **entity filter** is mandatory and defines generic search criteria. " + + "For example, \"find all devices with profile 'Moisture Sensor'\" or \"Find all devices related to asset 'Building A'\"" + + "\n\nOptional **key filters** allow to filter results of the entity filter by complex criteria against " + + "main entity fields (name, label, type, etc), attributes and telemetry. " + + "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"."+ + "\n\nLet's review the example:" + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"entityFilter\": {\n" + + " \"type\": \"entityType\",\n" + + " \"entityType\": \"DEVICE\"\n" + + " },\n" + + " \"keyFilters\": [\n" + + " {\n" + + " \"key\": {\n" + + " \"type\": \"ATTRIBUTE\",\n" + + " \"key\": \"active\"\n" + + " },\n" + + " \"valueType\": \"BOOLEAN\",\n" + + " \"predicate\": {\n" + + " \"operation\": \"EQUAL\",\n" + + " \"value\": {\n" + + " \"defaultValue\": true,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"BOOLEAN\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + + ENTITY_FILTERS + + KEY_FILTERS + + TENANT_AND_USER_AUTHORITY_PARAGRAPH;; + + private static final String ENTITY_DATA_QUERY_DESCRIPTION = + "Allows to run complex queries over platform entities (devices, assets, customers, etc) " + + "based on the combination of main entity filter and multiple key filters. " + + "Returns the paginated result of the query that contains requested entity fields and latest values of requested attributes and time-series data.\n\n" + + "# Query Definition\n\n" + + "\n\nMain **entity filter** is mandatory and defines generic search criteria. " + + "For example, \"find all devices with profile 'Moisture Sensor'\" or \"Find all devices related to asset 'Building A'\"" + + "\n\nOptional **key filters** allow to filter results of the **entity filter** by complex criteria against " + + "main entity fields (name, label, type, etc), attributes and telemetry. " + + "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"."+ + "\n\nThe **entity fields** and **latest values** contains list of entity fields and latest attribute/telemetry fields to fetch for each entity." + + "\n\nThe **page link** contains information about the page to fetch and the sort ordering." + + "\n\nLet's review the example:" + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"entityFilter\": {\n" + + " \"type\": \"entityType\",\n" + + " \"resolveMultiple\": true,\n" + + " \"entityType\": \"DEVICE\"\n" + + " },\n" + + " \"keyFilters\": [\n" + + " {\n" + + " \"key\": {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " },\n" + + " \"valueType\": \"NUMERIC\",\n" + + " \"predicate\": {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 0,\n" + + " \"dynamicValue\": {\n" + + " \"sourceType\": \"CURRENT_USER\",\n" + + " \"sourceAttribute\": \"temperatureThreshold\",\n" + + " \"inherit\": false\n" + + " }\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"entityFields\": [\n" + + " {\n" + + " \"type\": \"ENTITY_FIELD\",\n" + + " \"key\": \"name\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ENTITY_FIELD\",\n" + + " \"key\": \"label\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ENTITY_FIELD\",\n" + + " \"key\": \"additionalInfo\"\n" + + " }\n" + + " ],\n" + + " \"latestValues\": [\n" + + " {\n" + + " \"type\": \"ATTRIBUTE\",\n" + + " \"key\": \"model\"\n" + + " },\n" + + " {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " }\n" + + " ],\n" + + " \"pageLink\": {\n" + + " \"page\": 0,\n" + + " \"pageSize\": 10,\n" + + " \"sortOrder\": {\n" + + " \"key\": {\n" + + " \"key\": \"name\",\n" + + " \"type\": \"ENTITY_FIELD\"\n" + + " },\n" + + " \"direction\": \"ASC\"\n" + + " }\n" + + " }\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + + ENTITY_FILTERS + + KEY_FILTERS + + TENANT_AND_USER_AUTHORITY_PARAGRAPH; + + + private static final String ALARM_DATA_QUERY_DESCRIPTION = "This method description defines how Alarm Data Query extends the Entity Data Query. " + + "See method 'Find Entity Data by Query' first to get the info about 'Entity Data Query'." + + "\n\n The platform will first search the entities that match the entity and key filters. Then, the platform will use 'Alarm Page Link' to filter the alarms related to those entities. " + + "Finally, platform fetch the properties of alarm that are defined in the **'alarmFields'** and combine them with the other entity, attribute and latest time-series fields to return the result. " + + "\n\n See example of the alarm query below. The query will search first 100 active alarms with type 'Temperature Alarm' or 'Fire Alarm' for any device with current temperature > 0. " + + "The query will return combination of the entity fields: name of the device, device model and latest temperature reading and alarms fields: createdTime, type, severity and status: " + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"entityFilter\": {\n" + + " \"type\": \"entityType\",\n" + + " \"resolveMultiple\": true,\n" + + " \"entityType\": \"DEVICE\"\n" + + " },\n" + + " \"pageLink\": {\n" + + " \"page\": 0,\n" + + " \"pageSize\": 100,\n" + + " \"textSearch\": null,\n" + + " \"searchPropagatedAlarms\": false,\n" + + " \"statusList\": [\n" + + " \"ACTIVE\"\n" + + " ],\n" + + " \"severityList\": [\n" + + " \"CRITICAL\",\n" + + " \"MAJOR\"\n" + + " ],\n" + + " \"typeList\": [\n" + + " \"Temperature Alarm\",\n" + + " \"Fire Alarm\"\n" + + " ],\n" + + " \"sortOrder\": {\n" + + " \"key\": {\n" + + " \"key\": \"createdTime\",\n" + + " \"type\": \"ALARM_FIELD\"\n" + + " },\n" + + " \"direction\": \"DESC\"\n" + + " },\n" + + " \"timeWindow\": 86400000\n" + + " },\n" + + " \"keyFilters\": [\n" + + " {\n" + + " \"key\": {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " },\n" + + " \"valueType\": \"NUMERIC\",\n" + + " \"predicate\": {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 0,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"alarmFields\": [\n" + + " {\n" + + " \"type\": \"ALARM_FIELD\",\n" + + " \"key\": \"createdTime\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ALARM_FIELD\",\n" + + " \"key\": \"type\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ALARM_FIELD\",\n" + + " \"key\": \"severity\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ALARM_FIELD\",\n" + + " \"key\": \"status\"\n" + + " }\n" + + " ],\n" + + " \"entityFields\": [\n" + + " {\n" + + " \"type\": \"ENTITY_FIELD\",\n" + + " \"key\": \"name\"\n" + + " }\n" + + " ],\n" + + " \"latestValues\": [\n" + + " {\n" + + " \"type\": \"ATTRIBUTE\",\n" + + " \"key\": \"model\"\n" + + " },\n" + + " {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " }\n" + + " ]\n" + + "}"+ + MARKDOWN_CODE_BLOCK_END + + ""; + @Autowired private EntityQueryService entityQueryService; private static final int MAX_PAGE_SIZE = 100; + @ApiOperation(value = "Count Entities by Query", + notes = ENTITY_COUNT_QUERY_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/count", method = RequestMethod.POST) @ResponseBody - public long countEntitiesByQuery(@RequestBody EntityCountQuery query) throws ThingsboardException { + public long countEntitiesByQuery( + @ApiParam(value = "A JSON value representing the entity count query. See API call notes above for more details.") + @RequestBody EntityCountQuery query) throws ThingsboardException { checkNotNull(query); try { return this.entityQueryService.countEntitiesByQuery(getCurrentUser(), query); @@ -59,10 +697,14 @@ public class EntityQueryController extends BaseController { } } + @ApiOperation(value = "Find Entity Data by Query", + notes = ENTITY_DATA_QUERY_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/find", method = RequestMethod.POST) @ResponseBody - public PageData findEntityDataByQuery(@RequestBody EntityDataQuery query) throws ThingsboardException { + public PageData findEntityDataByQuery( + @ApiParam(value = "A JSON value representing the entity data query. See API call notes above for more details.") + @RequestBody EntityDataQuery query) throws ThingsboardException { checkNotNull(query); try { return this.entityQueryService.findEntityDataByQuery(getCurrentUser(), query); @@ -71,10 +713,14 @@ public class EntityQueryController extends BaseController { } } + @ApiOperation(value = "Find Alarms by Query", + notes = ALARM_DATA_QUERY_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarmsQuery/find", method = RequestMethod.POST) @ResponseBody - public PageData findAlarmDataByQuery(@RequestBody AlarmDataQuery query) throws ThingsboardException { + public PageData findAlarmDataByQuery( + @ApiParam(value = "A JSON value representing the alarm data query. See API call notes above for more details.") + @RequestBody AlarmDataQuery query) throws ThingsboardException { checkNotNull(query); try { return this.entityQueryService.findAlarmDataByQuery(getCurrentUser(), query); @@ -83,12 +729,18 @@ public class EntityQueryController extends BaseController { } } + @ApiOperation(value = "Find Entity Keys by Query", + notes = "Uses entity data query (see 'Find Entity Data by Query') to find first 100 entities. Then fetch and return all unique time-series and/or attribute keys. Used mostly for UI hints.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/find/keys", method = RequestMethod.POST) @ResponseBody - public DeferredResult findEntityTimeseriesAndAttributesKeysByQuery(@RequestBody EntityDataQuery query, - @RequestParam("timeseries") boolean isTimeseries, - @RequestParam("attributes") boolean isAttributes) throws ThingsboardException { + public DeferredResult findEntityTimeseriesAndAttributesKeysByQuery( + @ApiParam(value = "A JSON value representing the entity data query. See API call notes above for more details.") + @RequestBody EntityDataQuery query, + @ApiParam(value = "Include all unique time-series keys to the result.") + @RequestParam("timeseries") boolean isTimeseries, + @ApiParam(value = "Include all unique attribute keys to the result.") + @RequestParam("attributes") boolean isAttributes) throws ThingsboardException { TenantId tenantId = getTenantId(); checkNotNull(query); try { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityCountQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityCountQuery.java index 07878a3347..a66a6c0954 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityCountQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityCountQuery.java @@ -15,11 +15,13 @@ */ package org.thingsboard.server.common.data.query; +import io.swagger.annotations.ApiModel; import lombok.Getter; import java.util.Collections; import java.util.List; +@ApiModel public class EntityCountQuery { @Getter diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityKey.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityKey.java index 233af353d1..2aba65c6a8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityKey.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityKey.java @@ -15,10 +15,12 @@ */ package org.thingsboard.server.common.data.query; +import io.swagger.annotations.ApiModel; import lombok.Data; import java.io.Serializable; +@ApiModel @Data public class EntityKey implements Serializable { private final EntityKeyType type; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilter.java index 1b1ec51314..94884ef96a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilter.java @@ -15,10 +15,12 @@ */ package org.thingsboard.server.common.data.query; +import io.swagger.annotations.ApiModel; import lombok.Data; import java.io.Serializable; +@ApiModel @Data public class KeyFilter implements Serializable { From 62823f6f73f3fd88b42c4db2d609d9801af403a3 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 18 Oct 2021 13:10:11 +0300 Subject: [PATCH 082/303] Improve markdown component. Add more help content. --- ui-ngx/angular.json | 1 + .../mobile-action-editor.component.html | 8 + .../action/mobile-action-editor.models.ts | 6 - .../data-key-config-dialog.component.html | 2 +- .../widget/lib/markdown-widget.component.html | 2 +- .../pages/widget/widget-editor.component.html | 1 + .../pages/widget/widget-editor.component.scss | 18 +- .../components/help-markdown.component.html | 4 +- .../components/help-popup.component.html | 26 ++- .../components/help-popup.component.scss | 56 ++---- .../shared/components/help-popup.component.ts | 32 ++- .../shared/components/markdown.component.html | 26 +++ .../shared/components/markdown.component.ts | 75 +++++-- .../components/marked-options.service.ts | 26 ++- .../en_US/widget/action/custom_action_args.md | 19 ++ .../en_US/widget/action/custom_action_fn.md | 13 +- .../widget/action/custom_additional_params.md | 97 ++++----- .../widget/action/custom_pretty_action_fn.md | 13 +- .../widget/action/mobile_get_location_fn.md | 49 +++++ .../action/mobile_get_phone_number_fn.md | 48 +++++ .../action/mobile_handle_empty_result_fn.md | 31 +++ .../widget/action/mobile_handle_error_fn.md | 33 ++++ .../widget/action/mobile_process_image_fn.md | 92 +++++++++ .../action/mobile_process_launch_result_fn.md | 33 ++++ .../action/mobile_process_location_fn.md | 59 ++++++ .../action/mobile_process_qr_code_fn.md | 76 +++++++ .../widget/editor/examples/alarm_widget.md | 147 ++++++++++++++ .../examples/ext_latest_values_example.md | 67 +++++++ .../editor/examples/ext_timeseries_example.md | 112 +++++++++++ .../editor/examples/latest_values_widget.md | 47 +++++ .../widget/editor/examples/rpc_widget.md | 187 ++++++++++++++++++ .../widget/editor/examples/static_widget.md | 72 +++++++ .../editor/examples/timeseries_widget.md | 93 +++++++++ .../editor/widget_js_action_sources_object.md | 17 ++ .../widget/editor/widget_js_existing_code.md | 62 ++++++ .../help/en_US/widget/editor/widget_js_fn.md | 135 +++++++++++++ .../editor/widget_js_subscription_object.md | 113 +++++++++++ .../widget_js_type_parameters_object.md | 14 ++ ui-ngx/src/styles.scss | 15 +- 39 files changed, 1773 insertions(+), 154 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/markdown.component.html create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/custom_action_args.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/mobile_get_location_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/mobile_get_phone_number_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/mobile_handle_empty_result_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/mobile_handle_error_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/mobile_process_image_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/mobile_process_launch_result_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/mobile_process_location_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/mobile_process_qr_code_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/examples/alarm_widget.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/examples/ext_latest_values_example.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/examples/ext_timeseries_example.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/examples/latest_values_widget.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/examples/rpc_widget.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/examples/static_widget.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/examples/timeseries_widget.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/widget_js_action_sources_object.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/widget_js_existing_code.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/widget_js_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/widget_js_subscription_object.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/editor/widget_js_type_parameters_object.md diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 5c24a0bfe3..a97e65b04c 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -97,6 +97,7 @@ "node_modules/prismjs/components/prism-bash.min.js", "node_modules/prismjs/components/prism-json.min.js", "node_modules/prismjs/components/prism-javascript.min.js", + "node_modules/prismjs/components/prism-typescript.min.js", "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js" ], "customWebpackConfig": { diff --git a/ui-ngx/src/app/modules/home/components/widget/action/mobile-action-editor.component.html b/ui-ngx/src/app/modules/home/components/widget/action/mobile-action-editor.component.html index 401dfb8bd7..90feadcc44 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/mobile-action-editor.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/action/mobile-action-editor.component.html @@ -37,6 +37,7 @@ [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel']" [globalVariables]="functionScopeVariables" [editorCompleter]="customActionEditorCompleter" + helpId="widget/action/mobile_get_location_fn" > @@ -46,6 +47,7 @@ [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel']" [globalVariables]="functionScopeVariables" [editorCompleter]="customActionEditorCompleter" + helpId="widget/action/mobile_get_phone_number_fn" > @@ -67,6 +70,7 @@ [functionArgs]="['code', 'format', '$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel']" [globalVariables]="functionScopeVariables" [editorCompleter]="customActionEditorCompleter" + helpId="widget/action/mobile_process_qr_code_fn" > @@ -76,6 +80,7 @@ [functionArgs]="['latitude', 'longitude', '$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel']" [globalVariables]="functionScopeVariables" [editorCompleter]="customActionEditorCompleter" + helpId="widget/action/mobile_process_location_fn" >
@@ -97,6 +103,7 @@ [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel']" [globalVariables]="functionScopeVariables" [editorCompleter]="customActionEditorCompleter" + helpId="widget/action/mobile_handle_empty_result_fn" >
diff --git a/ui-ngx/src/app/modules/home/components/widget/action/mobile-action-editor.models.ts b/ui-ngx/src/app/modules/home/components/widget/action/mobile-action-editor.models.ts index ea32b812be..14ca89288e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/mobile-action-editor.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/action/mobile-action-editor.models.ts @@ -111,12 +111,6 @@ const processLocationFunction = 'showLocationDialog(\'Location\', latitude, longitude);\n' + '// saveEntityLocationAttributes(\'latitude\', \'longitude\', latitude, longitude);\n' + '\n' + - 'function showImageDialog(title, imageUrl) {\n' + - ' setTimeout(function() {\n' + - ' widgetContext.customDialog.customDialog(imageDialogTemplate, ImageDialogController, {imageUrl: imageUrl, title: title}).subscribe();\n' + - ' }, 100);\n' + - '}\n' + - '\n' + 'function saveEntityLocationAttributes(latitudeAttributeName, longitudeAttributeName, latitude, longitude) {\n' + ' if (entityId) {\n' + ' let attributes = [\n' + diff --git a/ui-ngx/src/app/modules/home/components/widget/data-key-config-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/data-key-config-dialog.component.html index 4bbfb097bc..96c47dda92 100644 --- a/ui-ngx/src/app/modules/home/components/widget/data-key-config-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/data-key-config-dialog.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+

{{ 'datakey.configuration' | translate }}

diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.html index ae94d53f85..46069c15f0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.html @@ -15,4 +15,4 @@ limitations under the License. --> - + diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html index e4be9ab8a4..399c85b401 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html @@ -251,6 +251,7 @@ + - - {{triggerText}} - - + diff --git a/ui-ngx/src/app/shared/components/help-popup.component.scss b/ui-ngx/src/app/shared/components/help-popup.component.scss index c80b239d2d..e28445de66 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.scss +++ b/ui-ngx/src/app/shared/components/help-popup.component.scss @@ -15,16 +15,14 @@ */ .tb-help-popup-button { position: relative; -} -.tb-help-popup-button-loading { - background: #fff; - border-radius: 50%; - width: 32px !important; - height: 32px !important; - position: absolute; - top: 0; - left: 0; - &.mat-progress-spinner { + .mat-progress-spinner { + position: absolute; + top: 0; + left: 0; + background: #fff; + border-radius: 50%; + width: 32px !important; + height: 32px !important; svg { top: 6px; left: 6px; @@ -32,36 +30,20 @@ } } -.tb-help-popup-span { +.tb-help-popup-text-button { position: relative; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - color: #2a7dec; - font-weight: 500; - &.active.ready { - text-decoration: underline; + padding: 0 2px 0 8px; + line-height: 28px; + &.mat-stroked-button { + padding: 0 1px 0 7px; + line-height: 26px; } - &:hover { - &:not(.active) { - text-decoration: underline; - } + .mat-icon { + padding-left: 4px; } - &:after { + .mat-progress-spinner { display: inline-block; - font-family: "FontAwesome"; - content: '\f08e'; - padding-left: 5px; - font-size: 14px; - font-weight: 600; - } - .mat-progress-bar { - position: absolute; - height: 2px; - left: 0; - right: 0; - bottom: 0; + margin-left: 4px; + margin-right: 5px; } } diff --git a/ui-ngx/src/app/shared/components/help-popup.component.ts b/ui-ngx/src/app/shared/components/help-popup.component.ts index 0e27a16f5c..50566cc9d4 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.ts +++ b/ui-ngx/src/app/shared/components/help-popup.component.ts @@ -17,15 +17,17 @@ import { Component, ElementRef, - Input, + Input, OnChanges, OnDestroy, - Renderer2, + Renderer2, SimpleChanges, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core'; import { TbPopoverService } from '@shared/components/popover.service'; import { PopoverPlacement } from '@shared/components/popover.models'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { isDefinedAndNotNull } from '@core/utils'; @Component({ // tslint:disable-next-line:component-selector @@ -34,10 +36,10 @@ import { PopoverPlacement } from '@shared/components/popover.models'; styleUrls: ['./help-popup.component.scss'], encapsulation: ViewEncapsulation.None }) -export class HelpPopupComponent implements OnDestroy { +export class HelpPopupComponent implements OnChanges, OnDestroy { @ViewChild('toggleHelpButton', {read: ElementRef, static: false}) toggleHelpButton: ElementRef; - @ViewChild('toggleHelpSpan', {read: ElementRef, static: false}) toggleHelpSpan: ElementRef; + @ViewChild('toggleHelpTextButton', {read: ElementRef, static: false}) toggleHelpTextButton: ElementRef; // tslint:disable-next-line:no-input-rename @Input('tb-help-popup') helpId: string; @@ -45,6 +47,9 @@ export class HelpPopupComponent implements OnDestroy { // tslint:disable-next-line:no-input-rename @Input('trigger-text') triggerText: string; + // tslint:disable-next-line:no-input-rename + @Input('trigger-style') triggerStyle: string; + // tslint:disable-next-line:no-input-rename @Input('tb-help-popup-placement') helpPopupPlacement: PopoverPlacement; @@ -54,12 +59,27 @@ export class HelpPopupComponent implements OnDestroy { popoverVisible = false; popoverReady = true; + triggerSafeHtml: SafeHtml = null; + textMode = false; + constructor(private viewContainerRef: ViewContainerRef, + private element: ElementRef, + private sanitizer: DomSanitizer, private renderer: Renderer2, - private popoverService: TbPopoverService) {} + private popoverService: TbPopoverService) { + } + + ngOnChanges(changes: SimpleChanges): void { + if (isDefinedAndNotNull(this.triggerText)) { + this.triggerSafeHtml = this.sanitizer.bypassSecurityTrustHtml(this.triggerText); + } else { + this.triggerSafeHtml = null; + } + this.textMode = this.triggerSafeHtml != null; + } toggleHelp() { - const trigger = this.triggerText ? this.toggleHelpSpan.nativeElement : this.toggleHelpButton.nativeElement; + const trigger = this.textMode ? this.toggleHelpTextButton.nativeElement : this.toggleHelpButton.nativeElement; this.popoverService.toggleHelpPopover(trigger, this.renderer, this.viewContainerRef, this.helpId, '', diff --git a/ui-ngx/src/app/shared/components/markdown.component.html b/ui-ngx/src/app/shared/components/markdown.component.html new file mode 100644 index 0000000000..b854aa3364 --- /dev/null +++ b/ui-ngx/src/app/shared/components/markdown.component.html @@ -0,0 +1,26 @@ + + + +
+ {{error}} +
+
+
diff --git a/ui-ngx/src/app/shared/components/markdown.component.ts b/ui-ngx/src/app/shared/components/markdown.component.ts index c9fac8d9a7..1abfc5b9e6 100644 --- a/ui-ngx/src/app/shared/components/markdown.component.ts +++ b/ui-ngx/src/app/shared/components/markdown.component.ts @@ -18,7 +18,7 @@ import { ChangeDetectorRef, Component, ComponentFactory, - ComponentRef, + ComponentRef, ElementRef, EventEmitter, Inject, Injector, @@ -33,20 +33,17 @@ import { MarkdownService, PrismPlugin } from 'ngx-markdown'; import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { SHARED_MODULE_TOKEN } from '@shared/components/tokens'; +import { isDefinedAndNotNull } from '@core/utils'; +import { Observable, of, ReplaySubject } from 'rxjs'; @Component({ selector: 'tb-markdown', - template: '' + - '' + - '
' + - '{{error}}' + - '
' + templateUrl: './markdown.component.html' }) export class TbMarkdownComponent implements OnChanges { @ViewChild('markdownContainer', {read: ViewContainerRef, static: true}) markdownContainer: ViewContainerRef; + @ViewChild('fallbackElement', {static: true}) fallbackElement: ElementRef; @Input() data: string | undefined; @@ -58,9 +55,14 @@ export class TbMarkdownComponent implements OnChanges { get lineNumbers(): boolean { return this.lineNumbersValue; } set lineNumbers(value: boolean) { this.lineNumbersValue = coerceBooleanProperty(value); } + @Input() + get fallbackToPlainMarkdown(): boolean { return this.fallbackToPlainMarkdownValue; } + set fallbackToPlainMarkdown(value: boolean) { this.fallbackToPlainMarkdownValue = coerceBooleanProperty(value); } + @Output() ready = new EventEmitter(); private lineNumbersValue = false; + private fallbackToPlainMarkdownValue = false; isMarkdownReady = false; @@ -76,14 +78,14 @@ export class TbMarkdownComponent implements OnChanges { private dynamicComponentFactoryService: DynamicComponentFactoryService) {} ngOnChanges(changes: SimpleChanges): void { - if (this.data) { + if (isDefinedAndNotNull(this.data)) { this.render(this.data); } } private render(markdown: string) { - let template = this.markdownService.compile(markdown, false); - template = this.sanitizeCurlyBraces(template); + const compiled = this.markdownService.compile(markdown, false); + let template = this.sanitizeCurlyBraces(compiled); let markdownClass = 'tb-markdown-view'; if (this.markdownClass) { markdownClass += ` ${this.markdownClass}`; @@ -91,6 +93,7 @@ export class TbMarkdownComponent implements OnChanges { template = `
${template}
`; this.markdownContainer.clear(); const parent = this; + let readyObservable: Observable; this.dynamicComponentFactoryService.createDynamicComponentFactory( class TbMarkdownInstance { ngOnDestroy(): void { @@ -109,22 +112,40 @@ export class TbMarkdownComponent implements OnChanges { this.tbMarkdownInstanceComponentRef.instance.style = this.style; this.handlePlugins(this.tbMarkdownInstanceComponentRef.location.nativeElement); this.markdownService.highlight(this.tbMarkdownInstanceComponentRef.location.nativeElement); + readyObservable = this.handleImages(this.tbMarkdownInstanceComponentRef.location.nativeElement); this.error = null; } catch (error) { - this.error = (error ? error + '' : 'Failed to render markdown!').replace(/\n/g, '
'); - this.destroyMarkdownInstanceResources(); + readyObservable = this.handleError(compiled, error); } this.cd.detectChanges(); - this.ready.emit(); + readyObservable.subscribe(() => { + this.ready.emit(); + }); }, (error) => { - this.error = (error ? error + '' : 'Failed to render markdown!').replace(/\n/g, '
'); - this.destroyMarkdownInstanceResources(); + readyObservable = this.handleError(compiled, error); this.cd.detectChanges(); - this.ready.emit(); + readyObservable.subscribe(() => { + this.ready.emit(); + }); }); } + private handleError(template: string, error): Observable { + this.error = (error ? error + '' : 'Failed to render markdown!').replace(/\n/g, '
'); + this.destroyMarkdownInstanceResources(); + if (this.fallbackToPlainMarkdownValue) { + this.markdownContainer.clear(); + const element = this.fallbackElement.nativeElement; + element.innerHTML = template; + this.handlePlugins(element); + this.markdownService.highlight(element); + return this.handleImages(element); + } else { + return of(null); + } + } + private handlePlugins(element: HTMLElement): void { if (this.lineNumbers) { this.setPluginClass(element, PrismPlugin.LineNumbers); @@ -139,6 +160,26 @@ export class TbMarkdownComponent implements OnChanges { } } + private handleImages(element: HTMLElement): Observable { + const imgs = $('img', element); + if (imgs.length) { + let totalImages = imgs.length; + const imagesLoadedSubject = new ReplaySubject(); + imgs.each((index, img) => { + $(img).one('load error', () => { + totalImages--; + if (totalImages === 0) { + imagesLoadedSubject.next(); + imagesLoadedSubject.complete(); + } + }); + }); + return imagesLoadedSubject.asObservable(); + } else { + return of(null); + } + } + private sanitizeCurlyBraces(template: string): string { return template.replace(/{/g, '{').replace(/}/g, '}'); } diff --git a/ui-ngx/src/app/shared/components/marked-options.service.ts b/ui-ngx/src/app/shared/components/marked-options.service.ts index 89ed434e70..1666ca590e 100644 --- a/ui-ngx/src/app/shared/components/marked-options.service.ts +++ b/ui-ngx/src/app/shared/components/marked-options.service.ts @@ -21,6 +21,7 @@ import { DOCUMENT } from '@angular/common'; import { WINDOW } from '@core/services/window.service'; const copyCodeBlock = '{:copy-code}'; +const autoBlock = '{:auto}'; const targetBlankBlock = '{:target="_blank"}'; // @dynamic @@ -48,13 +49,25 @@ export class MarkedOptionsService extends MarkedOptions { this.renderer.code = (code: string, language: string | undefined, isEscaped: boolean) => { if (code.endsWith(copyCodeBlock)) { code = code.substring(0, code.length - copyCodeBlock.length); - const content = checkLineNumbers(this.renderer2.code(code, language, isEscaped), code); + const content = postProcessCodeContent(this.renderer2.code(code, language, isEscaped), code); this.id++; return this.wrapCopyCode(this.id, content, code); } else { - return this.wrapDiv(checkLineNumbers(this.renderer2.code(code, language, isEscaped), code)); + return this.wrapDiv(postProcessCodeContent(this.renderer2.code(code, language, isEscaped), code)); } }; + this.renderer.table = (header: string, body: string) => { + let autoLayout = false; + if (header.includes(autoBlock)) { + autoLayout = true; + header = header.replace(autoBlock, ''); + } + let table = this.renderer2.table(header, body); + if (autoLayout) { + table = table.replace('', '
');
+    replacement = '
';
+  } else {
+    replacement = '
';
   }
-  return content;
+  return content.replace('
', replacement);
 }
diff --git a/ui-ngx/src/assets/help/en_US/widget/action/custom_action_args.md b/ui-ngx/src/assets/help/en_US/widget/action/custom_action_args.md
new file mode 100644
index 0000000000..c8f1b508f6
--- /dev/null
+++ b/ui-ngx/src/assets/help/en_US/widget/action/custom_action_args.md
@@ -0,0 +1,19 @@
+  
  • $event: MouseEvent - The MouseEvent object. Usually a result of a mouse click event. +
  • +
  • widgetContext: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
  • +
  • entityId: string - An optional string id of the target entity. +
  • +
  • entityName: string - An optional string name of the target entity. +
  • +
  • additionalParams: {[key: string]: any} - An optional key/value object holding additional entity parameters. + + +
  • +
  • entityLabel: string - An optional string label of the target entity. +
  • diff --git a/ui-ngx/src/assets/help/en_US/widget/action/custom_action_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/custom_action_fn.md index a71cb598d0..de5eec3943 100644 --- a/ui-ngx/src/assets/help/en_US/widget/action/custom_action_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/action/custom_action_fn.md @@ -10,18 +10,7 @@ A JavaScript function performing custom action. **Parameters:**
      -
    • $event: MouseEvent - The MouseEvent object. Usually a result of a mouse click event. -
    • -
    • widgetContext: WidgetContext - A reference to WidgetContext that has all necessary API - and data used by widget instance. -
    • -
    • entityId: string - An optional string id of the target entity. -
    • -
    • entityName: string - An optional string name of the target entity. -
    • - {% include widget/action/custom_additional_params %} -
    • entityLabel: string - An optional string label of the target entity. -
    • + {% include widget/action/custom_action_args %}
    diff --git a/ui-ngx/src/assets/help/en_US/widget/action/custom_additional_params.md b/ui-ngx/src/assets/help/en_US/widget/action/custom_additional_params.md index c71e2b63b8..d13af3fc26 100644 --- a/ui-ngx/src/assets/help/en_US/widget/action/custom_additional_params.md +++ b/ui-ngx/src/assets/help/en_US/widget/action/custom_additional_params.md @@ -1,46 +1,53 @@ -
  • additionalParams: {[key: string]: any} - An optional key/value object holding additional entity parameters depending on widget type and action source: -
      -
    • Entities table widget (On row click or Action cell button) - additionalParams: { entity: EntityData }: -
        -
      • entity: EntityData - An - EntityData object - presenting basic entity properties (ex. id, entityName) and
        provides access to other entity attributes/timeseries declared in widget datasource configuration. -
      • -
      -
    • -
    • Alarms table widget (On row click or Action cell button) - additionalParams: { alarm: AlarmDataInfo }: -
        -
      • alarm: AlarmDataInfo - An - AlarmDataInfo object - presenting basic alarm properties (ex. type, severity, originator, etc.) and
        provides access to other alarm or originator entity fields/attributes/timeseries declared in widget datasource configuration. -
      • -
      -
    • -
    • Timeseries table widget (On row click or Action cell button) - additionalParams: TimeseriesRow: -
        -
      • additionalParams: TimeseriesRow - A - TimeseriesRow object - presenting formattedTs (a string value of formatted timestamp) and
        timeseries values for each column declared in widget datasource configuration. -
      • -
      -
    • -
    • Entities hierarchy widget (On node selected) - additionalParams: { nodeCtx: HierarchyNodeContext }: -
        -
      • nodeCtx: HierarchyNodeContext - An - HierarchyNodeContext object - containing entity field holding basic entity properties
        (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. -
      • -
      -
    • -
    • Pie - Flot widget (On slice click) - additionalParams: TbFlotPlotItem: -
        -
      • additionalParams: TbFlotPlotItem - A - TbFlotPlotItem object - containing series field with information about datasource and
        data key of clicked pie slice. -
      • -
      -
    • -
    • All other widgets - does not provide additionalParams value. -
    • -
    +#### Additional params object + +
    +
    + +additionalParams: {[key: string]: any} + +An optional key/value object holding additional entity parameters depending on widget type and action source: + +
      +
    • Entities table widget (On row click or Action cell button) - additionalParams: { entity: EntityData }: +
        +
      • entity: EntityData - An + EntityData object + presenting basic entity properties (ex. id, entityName) and
        provides access to other entity attributes/timeseries declared in widget datasource configuration. +
      • +
      +
    • +
    • Alarms table widget (On row click or Action cell button) - additionalParams: { alarm: AlarmDataInfo }: +
        +
      • alarm: AlarmDataInfo - An + AlarmDataInfo object + presenting basic alarm properties (ex. type, severity, originator, etc.) and
        provides access to other alarm or originator entity fields/attributes/timeseries declared in widget datasource configuration. +
      • +
      +
    • +
    • Timeseries table widget (On row click or Action cell button) - additionalParams: TimeseriesRow: +
        +
      • additionalParams: TimeseriesRow - A + TimeseriesRow object + presenting formattedTs (a string value of formatted timestamp) and
        timeseries values for each column declared in widget datasource configuration. +
      • +
      +
    • +
    • Entities hierarchy widget (On node selected) - additionalParams: { nodeCtx: HierarchyNodeContext }: +
        +
      • nodeCtx: HierarchyNodeContext - An + HierarchyNodeContext object + containing entity field holding basic entity properties
        (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. +
      • +
      +
    • +
    • Pie - Flot widget (On slice click) - additionalParams: TbFlotPlotItem: +
        +
      • additionalParams: TbFlotPlotItem - A + TbFlotPlotItem object + containing series field with information about datasource and
        data key of clicked pie slice. +
      • +
    • +
    • All other widgets - does not provide additionalParams value. +
    • +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/action/custom_pretty_action_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/custom_pretty_action_fn.md index a9fea185c3..a4c20a7cad 100644 --- a/ui-ngx/src/assets/help/en_US/widget/action/custom_pretty_action_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/action/custom_pretty_action_fn.md @@ -21,7 +21,14 @@ A JavaScript function performing custom action with defined HTML template to ren
  • htmlTemplate: string - An optional HTML template string defined in HTML tab.
    Used to render custom dialog (see Examples for more details).
  • - {% include widget/action/custom_additional_params %} +
  • additionalParams: {[key: string]: any} - An optional key/value object holding additional entity parameters. + + +
  • entityLabel: string - An optional string label of the target entity.
  • @@ -38,6 +45,7 @@ A JavaScript function performing custom action with defined HTML template to ren tb-help-popup="widget/action/examples/custom_pretty_create_dialog_js" tb-help-popup-placement="top" [tb-help-popup-style]="{maxHeight: '50vh', maxWidth: '50vw'}" + trigger-style="font-size: 16px;" trigger-text="JavaScript function"> @@ -47,6 +55,7 @@ A JavaScript function performing custom action with defined HTML template to ren tb-help-popup="widget/action/examples/custom_pretty_create_dialog_html" tb-help-popup-placement="top" [tb-help-popup-style]="{maxHeight: '50vh', maxWidth: '50vw'}" + trigger-style="font-size: 16px;" trigger-text="HTML code"> @@ -58,6 +67,7 @@ A JavaScript function performing custom action with defined HTML template to ren tb-help-popup="widget/action/examples/custom_pretty_edit_dialog_js" tb-help-popup-placement="top" [tb-help-popup-style]="{maxHeight: '50vh', maxWidth: '50vw'}" + trigger-style="font-size: 16px;" trigger-text="JavaScript function"> @@ -67,6 +77,7 @@ A JavaScript function performing custom action with defined HTML template to ren tb-help-popup="widget/action/examples/custom_pretty_edit_dialog_html" tb-help-popup-placement="top" [tb-help-popup-style]="{maxHeight: '50vh', maxWidth: '50vw'}" + trigger-style="font-size: 16px;" trigger-text="HTML code"> diff --git a/ui-ngx/src/assets/help/en_US/widget/action/mobile_get_location_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/mobile_get_location_fn.md new file mode 100644 index 0000000000..c504ac1b67 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/mobile_get_location_fn.md @@ -0,0 +1,49 @@ +#### Get location function + +
    +
    + +*function getLocation($event, widgetContext, entityId, entityName, additionalParams, entityLabel): [number, number] | Observable<[number, number]>* + +A JavaScript function that should return location as array of two numbers (latitude, longitude) for further processing by mobile action.
    +Usually location can be obtained from entity attributes/telemetry. + +**Parameters:** + +
      + {% include widget/action/custom_action_args %} +
    + +**Returns:** + +Latitude and longitude as array of two numbers or Observable of array of two numbers. For example ```[37.689, -122.433]```. + +
    + +##### Examples + +* Return location from entity attributes: + +```javascript +return getLocationFromEntityAttributes(); + +function getLocationFromEntityAttributes() { + if (entityId) { + return widgetContext.attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE', ['latitude', 'longitude']) + .pipe(widgetContext.rxjs + .map(function(attributeData) { + var res = [0,0]; + if (attributeData && attributeData.length === 2) { + res[0] = attributeData.filter(function (data) { return data.key === 'latitude'})[0].value; + res[1] = attributeData.filter(function (data) { return data.key === 'longitude'})[0].value; + } + return res; + } + ) + ); + } else { + return [0,0]; + } +} +{:copy-code} +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/action/mobile_get_phone_number_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/mobile_get_phone_number_fn.md new file mode 100644 index 0000000000..752d9a3909 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/mobile_get_phone_number_fn.md @@ -0,0 +1,48 @@ +#### Get phone number function + +
    +
    + +*function getPhoneNumber($event, widgetContext, entityId, entityName, additionalParams, entityLabel): number | string | Observable<number> | Observable<string>* + +A JavaScript function that should return phone number for further processing by mobile action.
    +Usually phone number can be obtained from entity attributes/telemetry. + +**Parameters:** + +
      + {% include widget/action/custom_action_args %} +
    + +**Returns:** + +String or numeric value of phone number or Observable of string or numeric value. For example ```123456789```. + +
    + +##### Examples + +* Return phone number from entity attributes: + +```javascript +return getPhoneNumberFromEntityAttributes(); + +function getPhoneNumberFromEntityAttributes() { + if (entityId) { + return widgetContext.attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE', ['phone']) + .pipe(widgetContext.rxjs + .map(function(attributeData) { + var res = 0; + if (attributeData && attributeData.length === 1) { + res = attributeData[0].value; + } + return res; + } + ) + ); + } else { + return 0; + } +} +{:copy-code} +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/action/mobile_handle_empty_result_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/mobile_handle_empty_result_fn.md new file mode 100644 index 0000000000..9722c3ea5a --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/mobile_handle_empty_result_fn.md @@ -0,0 +1,31 @@ +#### Handle empty result function + +
    +
    + +*function handleEmptyResult($event, widgetContext, entityId, entityName, additionalParams, entityLabel): void* + +An optional JavaScript function to handle empty result.
    Usually this happens when user cancels the action (for ex. by pressing phone back button). + +**Parameters:** + +
      + {% include widget/action/custom_action_args %} +
    + +
    + +##### Examples + +* Display alert dialog with canceled action message: + +```javascript +showEmptyResultDialog('Action was canceled!'); + +function showEmptyResultDialog(message) { + setTimeout(function() { + widgetContext.dialogs.alert('Empty result', message).subscribe(); + }, 100); +} +{:copy-code} +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/action/mobile_handle_error_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/mobile_handle_error_fn.md new file mode 100644 index 0000000000..01bf76c8fd --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/mobile_handle_error_fn.md @@ -0,0 +1,33 @@ +#### Handle error function + +
    +
    + +*function handleError(error, $event, widgetContext, entityId, entityName, additionalParams, entityLabel): void* + +An optional JavaScript function to handle error occurred while mobile action execution. + +**Parameters:** + +
      +
    • error: string - error message. +
    • + {% include widget/action/custom_action_args %} +
    + +
    + +##### Examples + +* Display alert dialog with error message: + +```javascript +showErrorDialog('Failed to perform action', error); + +function showErrorDialog(title, error) { + setTimeout(function() { + widgetContext.dialogs.alert(title, error).subscribe(); + }, 100); +} +{:copy-code} +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_image_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_image_fn.md new file mode 100644 index 0000000000..5759571fe7 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_image_fn.md @@ -0,0 +1,92 @@ +#### Process image function + +
    +
    + +*function processImage(imageUrl, $event, widgetContext, entityId, entityName, additionalParams, entityLabel): void* + +A JavaScript function to process image obtained as a result of mobile action (take photo, take image from gallery, etc.). + +**Parameters:** + +
      +
    • imageUrl: string - An image URL in base64 data format. +
    • + {% include widget/action/custom_action_args %} +
    + +
    + +##### Examples + +* Store image url data to entity attribute: + +```javascript +saveEntityImageAttribute('image', imageUrl); + +function saveEntityImageAttribute(attributeName, imageUrl) { + if (entityId) { + let attributes = [{ + key: attributeName, value: imageUrl + }]; + widgetContext.attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributes).subscribe( + function() { + widgetContext.showSuccessToast('Image attribute saved!'); + }, + function(error) { + widgetContext.dialogs.alert('Image attribute save failed', JSON.stringify(error)); + } + ); + } +} +{:copy-code} +``` + +* Display dialog with obtained image: + +```javascript +showImageDialog('Image', imageUrl); + +function showImageDialog(title, imageUrl) { + setTimeout(function() { + widgetContext.customDialog.customDialog(imageDialogTemplate, ImageDialogController, {imageUrl: imageUrl, title: title}).subscribe(); + }, 100); +} + +var imageDialogTemplate = + '
    ' + + '' + + '' + + '

    {{title}}

    ' + + '' + + '' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '' + + '' + + '
    ' + + '' + + '
    '; + +function ImageDialogController(instance) { + let vm = instance; + vm.title = vm.data.title; + vm.imageUrl = vm.data.imageUrl; + vm.close = function () + { + vm.dialogRef.close(null); + } +} +{:copy-code} +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_launch_result_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_launch_result_fn.md new file mode 100644 index 0000000000..ddcab07e18 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_launch_result_fn.md @@ -0,0 +1,33 @@ +#### Process launch result function + +
    +
    + +*function processLaunchResult(launched, $event, widgetContext, entityId, entityName, additionalParams, entityLabel): void* + +An optional JavaScript function to process result of attempt to launch external mobile application (for ex. map application or phone call application). + +**Parameters:** + +
      +
    • launched: boolean - boolean value indicating if the external application was successfully launched. + {% include widget/action/custom_action_args %} +
    + +
    + +##### Examples + +* Display alert dialog with external application launch status: + +```javascript +showLaunchStatusDialog('Application', launched); + +function showLaunchStatusDialog(title, status) { + setTimeout(function() { + widgetContext.dialogs.alert(title, status ? 'Successfully launched' : 'Failed to launch').subscribe(); + }, 100); +} + +{:copy-code} +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_location_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_location_fn.md new file mode 100644 index 0000000000..445053b1dd --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_location_fn.md @@ -0,0 +1,59 @@ +#### Process location function + +
    +
    + +*function processLocation(latitude, longitude, $event, widgetContext, entityId, entityName, additionalParams, entityLabel): void* + +A JavaScript function to process current location of the phone. + +**Parameters:** + +
      +
    • latitude: number - phone location latitude. +
    • +
    • longitude: number - phone location longitude. +
    • + {% include widget/action/custom_action_args %} +
    + +
    + +##### Examples + +* Display alert dialog with location data: + +```javascript +showLocationDialog('Location', latitude, longitude); + +function showLocationDialog(title, latitude, longitude) { + setTimeout(function() { + widgetContext.dialogs.alert(title, 'Latitude: '+latitude+'
    Longitude: ' + longitude).subscribe(); + }, 100); +} +{:copy-code} +``` + +* Store phone location to entity attributes: + +```javascript +saveEntityLocationAttributes('latitude', 'longitude', latitude, longitude); + +function saveEntityLocationAttributes(latitudeAttributeName, longitudeAttributeName, latitude, longitude) { + if (entityId) { + let attributes = [ + { key: latitudeAttributeName, value: latitude }, + { key: longitudeAttributeName, value: longitude } + ]; + widgetContext.attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributes).subscribe( + function() { + widgetContext.showSuccessToast('Location attributes saved!'); + }, + function(error) { + widgetContext.dialogs.alert('Location attributes save failed', JSON.stringify(error)); + } + ); + } +} +{:copy-code} +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_qr_code_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_qr_code_fn.md new file mode 100644 index 0000000000..6a011ead79 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/mobile_process_qr_code_fn.md @@ -0,0 +1,76 @@ +#### Process QR code function + +
    +
    + +*function processQrCode(code, format, $event, widgetContext, entityId, entityName, additionalParams, entityLabel): void* + +A JavaScript function to process result of barcode scanning. + +**Parameters:** + +
      +
    • code: string - A string value of scanned barcode. +
    • +
    • format: string - barcode format. See BarcodeFormat enum for possible values. +
    • + {% include widget/action/custom_action_args %} +
    + +
    + +##### Examples + +* Display alert dialog with scanned barcode: + +```javascript +showQrCodeDialog('Bar Code', code, format); + +function showQrCodeDialog(title, code, format) { + setTimeout(function() { + widgetContext.dialogs.alert(title, 'Code: ['+code+']
    Format: ' + format).subscribe(); + }, 100); +} +{:copy-code} +``` + +* Parse code as a device claiming info (in this case ```{deviceName: string, secretKey: string}```)
    and then claim device (see [Claiming devices{:target="_blank"}](${baseUrl}/docs/user-guide/claiming-devices/) for details): + +```javascript +var $scope = widgetContext.$scope; +var $injector = $scope.$injector; +var $translate = $injector.get(widgetContext.servicesMap.get('translate')); +var deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); +var deviceNotFound = $translate.instant('widgets.input-widgets.claim-not-found'); +var failedClaimDevice = $translate.instant('widgets.input-widgets.claim-failed'); +var claimDeviceInfo = JSON.parse(code); +var deviceName = claimDeviceInfo.deviceName; +var secretKey = claimDeviceInfo.secretKey; +var claimRequest = { + secretKey: secretKey +}; +deviceService.claimDevice(deviceName, claimRequest, { ignoreErrors: true }).subscribe( + function (data) { + widgetContext.showSuccessToast('Device \'' + deviceName + '\' successfully claimed!'); + widgetContext.updateAliases(); + }, + function (error) { + if(error.status == 404) { + widgetContext.showErrorToast(deviceNotFound); + } else { + if (error.status !== 400 && error.error && error.error.message) { + showDialog('Failed to claim device', error.error.message); + } else { + widgetContext.showErrorToast(failedClaimDevice); + } + } + } +); + +function showDialog(title, error) { + setTimeout(function() { + widgetContext.dialogs.alert(title, error).subscribe(); + }, 100); +} +{:copy-code} +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/examples/alarm_widget.md b/ui-ngx/src/assets/help/en_US/widget/editor/examples/alarm_widget.md new file mode 100644 index 0000000000..5d43c50db2 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/examples/alarm_widget.md @@ -0,0 +1,147 @@ +#### Sample Alarm widget + +
    +
    + +In the **Widgets Bundle** view, click the big “+” button at the bottom-right part of the screen and then click the “Create new widget type” button.
    +Click the **Alarm Widget** button on the **Select widget type** popup.
    +The **Widget Editor** will be opened, pre-populated with the content of the default **Alarm** template widget. + + - Replace content of the CSS tab in "Resources" section with the following one: + +```css +.my-alarm-table th { + text-align: left; +} +{:copy-code} +``` + + - Put the following HTML code inside the HTML tab of "Resources" section: + +```html +
    +
    My first Alarm widget.
    + + + + + + + + + + + +
    {{dataKey.label}}
    + {{getAlarmValue(alarm, dataKey)}} +
    +
    +{:copy-code} +``` + + - Put the following JSON content inside the "Settings schema" tab of **Settings schema section**: + +```json +{ + "schema": { + "type": "object", + "title": "AlarmTableSettings", + "properties": { + "alarmSeverityColorFunction": { + "title": "Alarm severity color function: f(severity)", + "type": "string", + "default": "if(severity == 'CRITICAL') {return 'red';} else if (severity == 'MAJOR') {return 'orange';} else return 'green'; " + } + }, + "required": [] + }, + "form": [ + { + "key": "alarmSeverityColorFunction", + "type": "javascript" + } + ] +} +{:copy-code} +``` + + - Put the following JavaScript code inside the "JavaScript" section: + +```javascript +self.onInit = function() { + var pageLink = self.ctx.pageLink(); + + pageLink.typeList = self.ctx.widgetConfig.alarmTypeList; + pageLink.statusList = self.ctx.widgetConfig.alarmStatusList; + pageLink.severityList = self.ctx.widgetConfig.alarmSeverityList; + pageLink.searchPropagatedAlarms = self.ctx.widgetConfig.searchPropagatedAlarms; + + self.ctx.defaultSubscription.subscribeForAlarms(pageLink, null); + self.ctx.$scope.alarmSource = self.ctx.defaultSubscription.alarmSource; + + var alarmSeverityColorFunctionBody = self.ctx.settings.alarmSeverityColorFunction; + if (typeof alarmSeverityColorFunctionBody === 'undefined' || !alarmSeverityColorFunctionBody.length) { + alarmSeverityColorFunctionBody = "if(severity == 'CRITICAL') {return 'red';} else if (severity == 'MAJOR') {return 'orange';} else return 'green';"; + } + + var alarmSeverityColorFunction = null; + try { + alarmSeverityColorFunction = new Function('severity', alarmSeverityColorFunctionBody); + } catch (e) { + alarmSeverityColorFunction = null; + } + + self.ctx.$scope.getAlarmValue = function(alarm, dataKey) { + var alarmKey = dataKey.name; + if (alarmKey === 'originator') { + alarmKey = 'originatorName'; + } + var value = alarm[alarmKey]; + if (alarmKey === 'createdTime') { + return self.ctx.date.transform(value, 'yyyy-MM-dd HH:mm:ss'); + } else { + return value; + } + } + + self.ctx.$scope.getAlarmCellStyle = function(alarm, dataKey) { + var alarmKey = dataKey.name; + if (alarmKey === 'severity' && alarmSeverityColorFunction) { + var severity = alarm[alarmKey]; + var color = alarmSeverityColorFunction(severity); + return { + color: color + }; + } + return {}; + } +} + +self.onDataUpdated = function() { + self.ctx.$scope.alarms = self.ctx.defaultSubscription.alarms.data; + self.ctx.detectChanges(); +} +{:copy-code} +``` + + - Click the **Run** button on the **Widget Editor Toolbar** in order to see the result in **Widget preview** section. + +![image](${baseUrl}/images/user-guide/contribution/widgets/alarm-widget-sample.png) + +In this example, the **alarmSource** and **alarms** properties of are assigned to **$scope** and become accessible within HTML template. + +Inside the HTML, a special [***ngFor**{:target="_blank"}](https://angular.io/api/common/NgForOf) structural angular directive is used in order to iterate over available alarm **dataKeys** of **alarmSource** and render corresponding columns. + +The table rows are rendered by iterating over **alarms** array and corresponding cells rendered by iterating over **dataKeys**. + +The function **getAlarmValue** is fetching alarm value and formatting **createdTime** alarm property using a [DatePipe{:target="_blank"}](https://angular.io/api/common/DatePipe) angular pipe accessible via **date** property of **ctx**. + +The function **getAlarmCellStyle** is used to assign custom cell styles for each alarm cell.
    In this example, we introduced new settings property called **alarmSeverityColorFunction** that contains function body returning color depending on alarm severity. + +Inside the **getAlarmCellStyle** function there is corresponding invocation of **alarmSeverityColorFunction** with severity value in order to get color for alarm severity cell. + +Note that in this code **onDataUpdated** function is implemented in order to update **alarms** property with latest alarms from subscription and invoke change detection using **detectChanges()** function. + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/examples/ext_latest_values_example.md b/ui-ngx/src/assets/help/en_US/widget/editor/examples/ext_latest_values_example.md new file mode 100644 index 0000000000..277bdac835 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/examples/ext_latest_values_example.md @@ -0,0 +1,67 @@ +#### Latest Values widget Example with gauge.js library + +
    +
    + +In this example, **Latest Values** gauge widget will be created using external [gauge.js{:target="_blank"}](http://bernii.github.io/gauge.js/) library. + +In the **Widgets Bundle** view, click the big “+” button at the bottom-right part of the screen, then click the “Create new widget type” button.
    +Click the **Latest Values** button on the **Select widget type** popup.
    +The **Widget Editor** will be opened, pre-populated with the content of default **Latest Values** template widget. + + - Open **Resources** tab and click "Add" then insert the following link: + +``` +https://bernii.github.io/gauge.js/dist/gauge.min.js +{:copy-code} +``` + + - Clear content of the CSS tab of "Resources" section. + - Put the following HTML code inside the HTML tab of "Resources" section: + +```html + +{:copy-code} +``` + + - Put the following JavaScript code inside the "JavaScript" section: + +```javascript +var canvasElement; +var gauge; + +self.onInit = function() { + canvasElement = $('#my-gauge', self.ctx.$container)[0]; + gauge = new Gauge(canvasElement); + gauge.minValue = -1000; + gauge.maxValue = 1000; + gauge.animationSpeed = 16; + self.onResize(); +} + +self.onResize = function() { + canvasElement.width = self.ctx.width; + canvasElement.height = self.ctx.height; + gauge.update(true); + gauge.render(); +} + +self.onDataUpdated = function() { + if (self.ctx.defaultSubscription.data[0].data.length) { + var value = self.ctx.defaultSubscription.data[0].data[0][1]; + gauge.set(value); + } +} +{:copy-code} +``` + + - Click the **Run** button on the **Widget Editor Toolbar** in order to see the result in **Widget preview** section. + +![image](${baseUrl}/images/user-guide/contribution/widgets/external-js-widget-sample.png) + +In this example, the external JS library API was used that becomes available after injecting the corresponding URL in **Resources** section. + +The value displayed was obtained from **data** property for the first dataKey. + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/examples/ext_timeseries_example.md b/ui-ngx/src/assets/help/en_US/widget/editor/examples/ext_timeseries_example.md new file mode 100644 index 0000000000..9c0e14fd42 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/examples/ext_timeseries_example.md @@ -0,0 +1,112 @@ +#### Time-Series widget Example with Chart.js library + +
    +
    + +In this example, **Time-Series** line chart widget will be created using external [Chart.js{:target="_blank"}](https://www.chartjs.org/) library. + +In the **Widgets Bundle** view, click the big “+” button at the bottom-right part of the screen, then click the “Create new widget type” button.
    +Click the **Time-Series** button on the **Select widget type** popup.
    +The **Widget Editor** will be opened, pre-populated with the content of default **Time-Series** template widget. + + - Open **Resources** tab and click "Add" then insert the following link: + +``` +https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js +{:copy-code} +``` + + - Clear content of the CSS tab of "Resources" section. + - Put the following HTML code inside the HTML tab of "Resources" section: + +```html + +{:copy-code} +``` + + - Put the following JavaScript code inside the "JavaScript" section: + +```javascript +var myChart; + +self.onInit = function() { + + var chartData = { + datasets: [] + }; + + for (var i=0; i < self.ctx.data.length; i++) { + var dataKey = self.ctx.data[i].dataKey; + var dataset = { + label: dataKey.label, + data: [], + borderColor: dataKey.color, + fill: false + }; + chartData.datasets.push(dataset); + } + + var options = { + maintainAspectRatio: false, + legend: { + display: false + }, + scales: { + xAxes: [{ + type: 'time', + ticks: { + maxRotation: 0, + autoSkipPadding: 30 + } + }] + } + }; + + var canvasElement = $('#myChart', self.ctx.$container)[0]; + var canvasCtx = canvasElement.getContext('2d'); + myChart = new Chart(canvasCtx, { + type: 'line', + data: chartData, + options: options + }); + self.onResize(); +} + +self.onResize = function() { + myChart.resize(); +} + +self.onDataUpdated = function() { + for (var i = 0; i < self.ctx.data.length; i++) { + var datasourceData = self.ctx.data[i]; + var dataSet = datasourceData.data; + myChart.data.datasets[i].data.length = 0; + var data = myChart.data.datasets[i].data; + for (var d = 0; d < dataSet.length; d++) { + var tsValuePair = dataSet[d]; + var ts = tsValuePair[0]; + var value = tsValuePair[1]; + data.push({t: ts, y: value}); + } + } + myChart.options.scales.xAxes[0].ticks.min = self.ctx.timeWindow.minTime; + myChart.options.scales.xAxes[0].ticks.max = self.ctx.timeWindow.maxTime; + myChart.update(); +} +{:copy-code} +``` + + - Click the **Run** button on the **Widget Editor Toolbar** in order to see the result in **Widget preview** section. + +![image](${baseUrl}/images/user-guide/contribution/widgets/external-js-timeseries-widget-sample.png) + +In this example, the external JS library API was used that becomes available after injecting the corresponding URL in **Resources** section. + +Initially chart datasets prepared using configured dataKeys from **data** property of **ctx**. + +In the **onDataUpdated** function datasources data converted to Chart.js line chart format and pushed to chart datasets. + +Please note that xAxis (time axis) is limited to current timewindow bounds obtained from **timeWindow** property of **ctx**. + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/examples/latest_values_widget.md b/ui-ngx/src/assets/help/en_US/widget/editor/examples/latest_values_widget.md new file mode 100644 index 0000000000..2cda617889 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/examples/latest_values_widget.md @@ -0,0 +1,47 @@ +#### Sample Latest Values widget + +
    +
    + +In the **Widgets Bundle** view, click the big “+” button at the bottom-right part of the screen and then click the “Create new widget type” button.
    +Click the **Latest Values** button on the **Select widget type** popup.
    +The **Widget Editor** will open, pre-populated with the content of the default **Latest Values** template widget. + + - Clear content of the CSS tab of "Resources" section. + - Put the following HTML code inside the HTML tab of "Resources" section: + +```html +
    +
    My first latest values widget.
    +
    +
    {{dataKeyData.dataKey.label}}:
    +
    {{(dataKeyData.data[0] && dataKeyData.data[0][0]) | date : 'yyyy-MM-dd HH:mm:ss' }}
    +
    {{dataKeyData.data[0] && dataKeyData.data[0][1]}}
    +
    +
    +{:copy-code} +``` + + - Put the following JavaScript code inside the "JavaScript" section: + +```javascript + self.onInit = function() { + self.ctx.$scope.data = self.ctx.defaultSubscription.data; + } + + self.onDataUpdated = function() { + self.ctx.detectChanges(); + } +{:copy-code} +``` + + - Click the **Run** button on the **Widget Editor Toolbar** in order to see the result in **Widget preview** section. + +![image](${baseUrl}/images/user-guide/contribution/widgets/latest-values-widget-sample.png) + +In this example, the **data** property of is assigned to the **$scope** and becomes accessible within the HTML template. + +Inside the HTML, a special [***ngFor**{:target="_blank"}](https://angular.io/api/common/NgForOf) structural angular directive is used in order to iterate over available dataKeys & datapoints then render latest values with their corresponding timestamps. + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/examples/rpc_widget.md b/ui-ngx/src/assets/help/en_US/widget/editor/examples/rpc_widget.md new file mode 100644 index 0000000000..d6f24b2055 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/examples/rpc_widget.md @@ -0,0 +1,187 @@ +#### Sample RPC (Control) widget + +
    +
    + +In the **Widgets Bundle** view, click the big “+” button at the bottom-right part of the screen and then click the “Create new widget type” button.
    +Click the **Control Widget** button on the **Select widget type** popup.
    +The **Widget Editor** will open, pre-populated with default **Control** template widget content. + + - Clear content of the CSS tab of "Resources" section. + - Put the following HTML code inside the HTML tab of "Resources" section: + +```html +
    +
    + + RPC method + + + RPC method name is required. + + + + RPC params + + + RPC params is required. + + + +
    + +
    +
    +
    +
    +
    +{:copy-code} +``` + + - Put the following JSON content inside the "Settings schema" tab of **Settings schema section**: + +```json +{ + "schema": { + "type": "object", + "title": "Settings", + "properties": { + "oneWayElseTwoWay": { + "title": "Is One Way Command", + "type": "boolean", + "default": true + }, + "requestTimeout": { + "title": "RPC request timeout", + "type": "number", + "default": 500 + } + }, + "required": [] + }, + "form": [ + "oneWayElseTwoWay", + "requestTimeout" + ] +} +{:copy-code} +``` + + - Put the following JavaScript code inside the "JavaScript" section: + +```javascript +self.onInit = function() { + + self.ctx.$scope.sendCommand = function() { + var rpcMethod = self.ctx.$scope.rpcMethod; + var rpcParams = self.ctx.$scope.rpcParams; + var timeout = self.ctx.settings.requestTimeout; + var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ? true : false; + + var commandObservable; + if (oneWayElseTwoWay) { + commandObservable = self.ctx.controlApi.sendOneWayCommand(rpcMethod, rpcParams, timeout); + } else { + commandObservable = self.ctx.controlApi.sendTwoWayCommand(rpcMethod, rpcParams, timeout); + } + commandObservable.subscribe( + function (response) { + if (oneWayElseTwoWay) { + self.ctx.$scope.rpcCommandResponse = "Command was successfully received by device.
    No response body because of one way command mode."; + } else { + self.ctx.$scope.rpcCommandResponse = "Response from device:
    "; + self.ctx.$scope.rpcCommandResponse += JSON.stringify(response, undefined, 2); + } + self.ctx.detectChanges(); + }, + function (rejection) { + self.ctx.$scope.rpcCommandResponse = "Failed to send command to the device:
    " + self.ctx.$scope.rpcCommandResponse += "Status: " + rejection.status + "
    "; + self.ctx.$scope.rpcCommandResponse += "Status text: '" + rejection.statusText + "'"; + self.ctx.detectChanges(); + } + + ); + } + +} +{:copy-code} +``` + + - Fill **Widget title** field with widget type name, for ex. "My first control widget". + - Click the **Run** button on the **Widget Editor Toolbar** in order to see the result in **Widget preview** section. + - Click dashboard edit button on the preview section to change the size of the resulting widget. Then click dashboard apply button. The final widget should look like the image below. + +![image](${baseUrl}/images/user-guide/contribution/widgets/control-widget-sample.png) + +- Click the **Save** button on the **Widget Editor Toolbar** to save widget type. + +To test how this widget performs RPC commands, we will need to place it in a dashboard then bind it to a device working with RPC commands. To do this, perform the following steps: + +- Login as Tenant administrator. +- Navigate to **Devices** and create new device with some name, for ex. "My RPC Device". +- Open device details and click "Copy Access Token" button to copy device access token to clipboard. +- Download [mqtt-js-rpc-from-server.sh{:target="_blank"}](${baseUrl}/docs/reference/resources/mqtt-js-rpc-from-server.sh) and [mqtt-js-rpc-from-server.js{:target="_blank"}](${baseUrl}/docs/reference/resources/mqtt-js-rpc-from-server.js). Place these files in a folder. + Edit **mqtt-js-rpc-from-server.sh** - replace **$ACCESS_TOKEN** with your device access token from the clipboard. And install mqtt client library. +- Run **mqtt-js-rpc-from-server.sh** script. You should see a "connected" message in the console. +- Navigate to **Dashboards** and create a new dashboard with some name, for ex. "My first control dashboard". Open this dashboard. +- Click dashboard "edit" button. In the dashboard edit mode, click the "Entity aliases" button located on the dashboard toolbar. + +![image](${baseUrl}/images/user-guide/contribution/widgets/dashboard-toolbar-entity-aliases.png) + +- Inside **Entity aliases** popup click "Add alias". +- Fill "Alias name" field, for ex. "My RPC Device Alias". +- Select "Entity list" in "Filter type" field. +- Choose "Device" in "Type" field. +- Select your device in "Entity list" field. In this example "My RPC Device". + +![image](${baseUrl}/images/user-guide/contribution/widgets/add-rpc-device-alias.png) + +- Click "Add" and then "Save" in **Entity aliases**. +- Click dashboard "+" button then click "Create new widget" button. + +![image](${baseUrl}/images/user-guide/contribution/widgets/dashboard-create-new-widget-button.png) + +- Then select **Widget Bundle** where your RPC widget was saved. Select "Control widget" tab. +- Click your widget. In this example, "My first control widget". +- From **Add Widget** popup, select your device alias in **Target device** section. In this example "My RPC Device Alias". +- Click **Add**. Your Control widget will appear in the dashboard. Click dashboard **Apply changes** button to save dashboard and leave editing mode. +- Fill **RPC method** field with RPC method name. For ex. "TestMethod". +- Fill **RPC params** field with RPC params. For ex. "{ param1: "value1" }". +- Click **Send RPC command** button. You should see the following response in the widget. + +![image](${baseUrl}/images/user-guide/contribution/widgets/control-widget-sample-response-one-way.png) + +The following output should be printed in the device console: + +```bash + request.topic: v1/devices/me/rpc/request/0 + request.body: {"method":"TestMethod","params":"{ param1: \"value1\" }"} +``` + +In order to test "Two way" RPC command mode, we need to change the corresponding widget settings property. To do this, perform the following steps: + +- Click dashboard "edit" button. In dashboard edit mode, click **Edit widget** button located in the header of Control widget. +- In the widget details, view select "Advanced" tab and uncheck "Is One Way Command" checkbox. + +![image](${baseUrl}/images/user-guide/contribution/widgets/control-widget-sample-settings.png) + +- Click **Apply changes** button on the widget details header. Close details and click dashboard **Apply changes** button. +- Fill widget fields with RPC method name and params like in previous steps. + Click **Send RPC command** button. You should see the following response in the widget. + +![image](${baseUrl}/images/user-guide/contribution/widgets/control-widget-sample-response-two-way.png) + +- stop **mqtt-js-rpc-from-server.sh** script. + Click **Send RPC command** button. You should see the following response in the widget. + +![image](${baseUrl}/images/user-guide/contribution/widgets/control-widget-sample-response-timeout.png) + +In this example, **controlApi** is used to send RPC commands. Additionally, custom widget settings were introduced in order to configure RPC command mode and RPC request timeout. + +The response from the device is handled by **commandObservable**. It has success and failed callbacks with corresponding response, or rejection objects containing information about request execution result. + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/examples/static_widget.md b/ui-ngx/src/assets/help/en_US/widget/editor/examples/static_widget.md new file mode 100644 index 0000000000..793da7c7c2 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/examples/static_widget.md @@ -0,0 +1,72 @@ +#### Sample Static widget + +
    +
    + +In the **Widgets Bundle** view, click the big “+” button at the bottom-right part of the screen and then click the “Create new widget type” button.
    +Click the **Static Widget** button on the **Select widget type** popup.
    +The **Widget Editor** will be opened pre-populated with the content of default **Static** template widget. + + - Put the following HTML code inside the HTML tab of "Resources" section: + +```html +
    +

    My first static widget.

    + +
    +{:copy-code} +``` + + - Put the following JSON content inside the "Settings schema" tab of **Settings schema section**: + +```json +{ + "schema": { + "type": "object", + "title": "Settings", + "properties": { + "alertContent": { + "title": "Alert content", + "type": "string", + "default": "Content derived from alertContent property of widget settings." + } + } + }, + "form": [ + "alertContent" + ] +} +{:copy-code} +``` + + - Put the following JavaScript code inside the "JavaScript" section: + +```javascript +self.onInit = function() { + + self.ctx.$scope.showAlert = function() { + var alertContent = self.ctx.settings.alertContent; + if (!alertContent) { + alertContent = "Content derived from alertContent property of widget settings."; + } + window.alert(alertContent); + }; + +} +{:copy-code} +``` + + - Click the **Run** button on the **Widget Editor Toolbar** to see the resulting **Widget preview** section. + +![image](${baseUrl}/images/user-guide/contribution/widgets/static-widget-sample.png) + +This is just a static HTML widget. There is no subscription data and no special widget API was used. + +Only custom **showAlert** function was implemented showing an alert with the content of **alertContent** property of widget settings. + +You can switch to dashboard edit mode in **Widget preview** section and change value of **alertContent** by changing widget settings in the "Advanced" tab of widget details. + +Then you can see that the new alert content is displayed. + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/examples/timeseries_widget.md b/ui-ngx/src/assets/help/en_US/widget/editor/examples/timeseries_widget.md new file mode 100644 index 0000000000..6dcffbe9e5 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/examples/timeseries_widget.md @@ -0,0 +1,93 @@ +#### Sample Time-Series widget + +
    +
    + +In the **Widgets Bundle** view, click the big “+” button at the bottom-right part of the screen, then click the “Create new widget type” button.
    +Click the **Time-Series** button on the **Select widget type** popup.
    +The **Widget Editor** will open, pre-populated with default **Time-Series** template widget content. + + - Replace content of the CSS tab in "Resources" section with the following one: + +```css +.my-data-table th { + text-align: left; +} +{:copy-code} +``` + + - Put the following HTML code inside the HTML tab of "Resources" section: + +```html + + + + + + + + + + + + + + + +
    Timestamp{{dataKeyData.dataKey.label}}
    {{data[0] | date : 'yyyy-MM-dd HH:mm:ss'}}{{dataKeyData.data[$dataIndex] && dataKeyData.data[$dataIndex][1]}}
    +
    +
    +{:copy-code} +``` + + - Put the following JavaScript code inside the "JavaScript" section: + +```javascript +self.onInit = function() { + self.ctx.widgetTitle = 'My first Time-Series widget'; + self.ctx.$scope.datasources = self.ctx.defaultSubscription.datasources; + self.ctx.$scope.data = self.ctx.defaultSubscription.data; + + self.ctx.$scope.datasourceData = []; + + var currentDatasource = null; + var currentDatasourceIndex = -1; + + for (var i=0;i **datasources** and **data** properties are assigned to **$scope** and become accessible within the HTML template. + +The **$scope.datasourceData** property is introduced to map datasource specific dataKeys data by datasource index for flexible access within the HTML template. + +Inside the HTML, a special [***ngFor**{:target="_blank"}](https://angular.io/api/common/NgForOf) structural angular directive is used in order to iterate over available datasources and render corresponding tabs. + +Inside each tab, the table is rendered using dataKeys obtained from **datasourceData** scope property accessed by datasource index.
    + +Each table renders columns by iterating over all **dataKeyData** objects and renders all available datapoints by iterating over **data** array of each **dataKeyData** to render timestamps and values. + +Note that in this code, **onDataUpdated** function is implemented with a call to **detectChanges** function necessary to perform new change detection cycle when new data is received. + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_action_sources_object.md b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_action_sources_object.md new file mode 100644 index 0000000000..16025b6cfd --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_action_sources_object.md @@ -0,0 +1,17 @@ +#### Action sources object + +
    +
    + +Map describing available widget action sources ([WidgetActionSource{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L121)) to which user actions can be assigned. It has the following structure: + +```javascript + return { + 'headerButton': { // Action source Id (unique action source identificator) + name: 'widget-action.header-button', // Display name of action source, used in widget settings ('Actions' tab). + value: 'headerButton', // Action source Id + multiple: true // Boolean property indicating if this action source supports multiple action definitions + // (for ex. multiple buttons in one cell, or only one action can by assigned on table row click.) + } + }; +``` diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_existing_code.md b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_existing_code.md new file mode 100644 index 0000000000..90585077a5 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_existing_code.md @@ -0,0 +1,62 @@ +#### Using existing JavaScript/Typescript code + +
    +
    + +Another approach of creating widgets is to use existing bundled JavaScript/Typescript code. + +In this case, you can create own TypeScript class or Angular component and bundle it into the ThingsBoard UI code. + +In order to make this code accessible within the widget, you need to register corresponding Angular module or inject TypeScript class to a global variable (for ex. window object). + +Some ThingsBoard widgets already use this approach. Take a look at the [widget-component-service.ts{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts#L140) +or [widget-components.module.ts{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts#L50).
    +Here you can find how some bundled classes or components are registered for later use in ThingsBoard widgets. + +For example "Timeseries - Flot" widget (from "Charts" Widgets Bundle) uses [**TbFlot**{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts#L73) TypeScript class which is injected as window property inside **widget-component-service.ts**: + +```typescript +... + +const widgetModulesTasks: Observable[] = []; +... + +widgetModulesTasks.push(from(import('@home/components/widget/lib/flot-widget')).pipe( + tap((mod) => { + (window as any).TbFlot = mod.TbFlot; + })) +); +... + +``` + +Another example is "Timeseries table" widget (from "Cards" Widgets Bundle) that uses Angular component [**tb-timeseries-table-widget**{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts#L107)
    which is registered as dependency of **WidgetComponentsModule** Angular module inside **widget-components.module.ts**. +Thereby this component becomes available for use inside the widget template HTML. + +```typescript +... + +import { TimeseriesTableWidgetComponent } from '@home/components/widget/lib/timeseries-table-widget.component'; + +... + +@NgModule({ + declarations: + [ +... + TimeseriesTableWidgetComponent, +... + ], +... + exports: [ +... + TimeseriesTableWidgetComponent, +... + ], +... +}) +export class WidgetComponentsModule { } +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_fn.md b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_fn.md new file mode 100644 index 0000000000..2c9cd63475 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_fn.md @@ -0,0 +1,135 @@ +#### Widget type JavaScript code + +
    +
    + +All widget related JavaScript code according to the [Widget API{:target="_blank"}](${baseUrl}/docs/user-guide/contribution/widgets-development/#basic-widget-api). +The built-in variable **self** is a reference to the widget instance.
    +Each widget function should be defined as a property of the **self** variable. +**self** variable has property **ctx** of type [WidgetContext{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L107) - a reference to widget context that has all necessary API and data used by widget instance. + +In order to implement a new widget, the following JavaScript functions should be defined *(Note: each function is optional and can be implemented according to widget specific behaviour):* + +|{:auto} **Function** | **Description** | +|------------------------------------|----------------------------------------------------------------------------------------| +| ``` onInit() ``` | The first function which is called when widget is ready for initialization. Should be used to prepare widget DOM, process widget settings and initial subscription information. | +| ``` onDataUpdated() ``` | Called when the new data is available from the widget subscription. Latest data can be accessed from the object of widget context (**ctx**). | +| ``` onResize() ``` | Called when widget container is resized. Latest width and height can be obtained from widget context (**ctx**). | +| ``` onEditModeChanged() ``` | Called when dashboard editing mode is changed. Latest mode is handled by isEdit property of **ctx**. | +| ``` onMobileModeChanged() ``` | Called when dashboard view width crosses mobile breakpoint. Latest state is handled by isMobile property of **ctx**. | +| ``` onDestroy() ``` | Called when widget element is destroyed. Should be used to cleanup all resources if necessary. | +| ``` getSettingsSchema() ``` | Optional function returning widget settings schema json as alternative to **Settings schema** of settings section. | +| ``` getDataKeySettingsSchema() ``` | Optional function returning particular data key settings schema json as alternative to **Data key settings schema** tab of settings section. | +| ``` typeParameters() ``` | Returns [WidgetTypeParameters{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L151) object describing widget datasource parameters. See | | +| ``` actionSources() ``` | Returns map describing available widget action sources ([WidgetActionSource{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L121)) used to define user actions. See | + +
    + +##### Creating simple widgets + +The tutorials below show how to create minimal widgets of each type. +In order to minimize the amount of code, the Angular framework will be used, on which ThingsBoard UI is actually based. +By the way, you can always use pure JavaScript or jQuery API in your widget code. + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    +
    + +
    + +##### Integrating existing code to create widget definition + +Below are some examples demonstrating how external JavaScript libraries or existing code can be reused/integrated to create new widgets. + +###### Using external JavaScript library + +
    + +
    +
    + +
    + +
    +
    + +###### Using existing JavaScript/Typescript code + +
    + +
    +
    + +
    + +##### Widget code debugging tips + +The most simple method of debugging is Web console output. +Just place [**console.log(...)**{:target="_blank"}](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) function inside any part of widget JavaScript code. +Then click **Run** button to restart widget code and observe debug information in the Web console. + +Another and most effective method of debugging is to invoke browser debugger. +Put [**debugger;**{:target="_blank"}](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger) statement into the place of widget code you are interested in and then click **Run** button to restart widget code. +Browser debugger (if enabled) will automatically pause code execution at the debugger statement and you will be able to analyze script execution using browser debugging tools. + +
    + +##### Further reading + +For more information read [Widgets Development Guide{:target="_blank"}](${baseUrl}/docs/user-guide/contribution/widgets-development). + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_subscription_object.md b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_subscription_object.md new file mode 100644 index 0000000000..4a92fd270e --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_subscription_object.md @@ -0,0 +1,113 @@ +#### Subscription object + +
    +
    + +The widget subscription object is instance of [IWidgetSubscription{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/core/api/widget-api.models.ts#L264") and contains all subscription information, including current data, according to the [widget type{:target="_blank"}](${baseUrl}/docs/user-guide/ui/widget-library/#widget-types). + +Depending on widget type, subscription object provides different data structures. +For [Latest values{:target="_blank"}](${baseUrl}/docs/user-guide/ui/widget-library/#latest-values) and [Time-series{:target="_blank"}](${baseUrl}/docs/user-guide/ui/widget-library/#time-series) widget types, it provides the following properties: + +- **datasources** - array of datasources (Array<[Datasource{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L279)>) used by this subscription, using the following structure: + +```javascript + datasources = [ + { // datasource + type: 'entity',// type of the datasource. Can be "function" or "entity" + name: 'name', // name of the datasource (in case of "entity" usually Entity name) + aliasName: 'aliasName', // name of the alias used to resolve this particular datasource Entity + entityName: 'entityName', // name of the Entity used as datasource + entityType: 'DEVICE', // datasource Entity type (for ex. "DEVICE", "ASSET", "TENANT", etc.) + entityId: '943b8cd0-576a-11e7-824c-0b1cb331ec92', // entity identificator presented as string uuid. + dataKeys: [ // array of keys (Array) (attributes or timeseries) of the entity used to fetch data + { // dataKey + name: 'name', // the name of the particular entity attribute/timeseries + type: 'timeseries', // type of the dataKey. Can be "timeseries", "attribute" or "function" + label: 'Sin', // label of the dataKey. Used as display value (for ex. in the widget legend section) + color: '#ffffff', // color of the key. Can be used by widget to set color of the key data (for ex. lines in line chart or segments in the pie chart). + funcBody: "", // only applicable for datasource with type "function" and "function" key type. Defines body of the function to generate simulated data. + settings: {} // dataKey specific settings with structure according to the defined Data key settings json schema. See "Settings schema section". + }, + //... + ] + }, + //... + ] +``` + +- **data** - array of latest data (Array<[DatasourceData{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L310)>) received in scope of this subscription, using the following structure: + +```javascript + data = [ + { + datasource: {}, // datasource object of this data. See datasource structure above. + dataKey: {}, // dataKey for which the data is held. See dataKey structure above. + data: [ // array of data points + [ // data point + 1498150092317, // unix timestamp of datapoint in milliseconds + 1, // value, can be either string, numeric or boolean + ], + //... + ] + }, + //... + ] +``` + +For [Alarm widget{:target="_blank"}](${baseUrl}/docs/user-guide/ui/widget-library/#alarm-widget) type it provides the following properties: + +- **alarmSource** - ([Datasource{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L279)) information about entity for which alarms are fetched, using the following structure: + +```javascript + alarmSource = { + type: 'entity',// type of the alarm source. Can be "function" or "entity" + name: 'name', // name of the alarm source (in case of "entity" usually Entity name) + aliasName: 'aliasName', // name of the alias used to resolve this particular alarm source Entity + entityName: 'entityName', // name of the Entity used as alarm source + entityType: 'DEVICE', // alarm source Entity type (for ex. "DEVICE", "ASSET", "TENANT", etc.) + entityId: '943b8cd0-576a-11e7-824c-0b1cb331ec92', // entity identificator presented as string uuid. + dataKeys: [ // array of keys indicating alarm fields used to display alarms data + { // dataKey + name: 'name', // the name of the particular alarm field + type: 'alarm', // type of the dataKey. Only "alarm" in this case. + label: 'Severity', // label of the dataKey. Used as display value (for ex. as a column title in the Alarms table) + color: '#ffffff', // color of the key. Can be used by widget to set color of the key data. + settings: {} // dataKey specific settings with structure according to the defined Data key settings json schema. See "Settings schema section". + }, + //... + ] + } +``` + +- **alarms** - array of alarms (Array<[Alarm{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/alarm.models.ts#L89)>) received in scope of this subscription, using the following structure: + +```javascript + alarms = [ + { // alarm + id: { // alarm id + entityType: "ALARM", + id: "943b8cd0-576a-11e7-824c-0b1cb331ec92" + }, + createdTime: 1498150092317, // Alarm created time (unix timestamp) + startTs: 1498150092316, // Alarm started time (unix timestamp) + endTs: 1498563899065, // Alarm end time (unix timestamp) + ackTs: 0, // Time of alarm acknowledgment (unix timestamp) + clearTs: 0, // Time of alarm clear (unix timestamp) + originator: { // Originator - id of entity produced this alarm + entityType: "ASSET", + id: "ceb16a30-4142-11e7-8b30-d5d66714ea5a" + }, + originatorName: "Originator Name", // Name of originator entity + type: "Temperature", // Type of the alarm + severity: "CRITICAL", // Severity of the alarm ("CRITICAL", "MAJOR", "MINOR", "WARNING", "INDETERMINATE") + status: "ACTIVE_UNACK", // Status of the alarm + // ("ACTIVE_UNACK" - active unacknowledged, + // "ACTIVE_ACK" - active acknowledged, + // "CLEARED_UNACK" - cleared unacknowledged, + // "CLEARED_ACK" - cleared acknowledged) + details: {} // Alarm details object derived from alarm details json. + } + ] +``` + +For [RPC{:target="_blank"}](${baseUrl}/docs/user-guide/ui/widget-library/#rpc-control-widget) or [Static{:target="_blank"}](${baseUrl}/docs/user-guide/ui/widget-library/#static) widget types, subscription object is optional and does not contain necessary information. diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_type_parameters_object.md b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_type_parameters_object.md new file mode 100644 index 0000000000..09ff8ccb93 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_type_parameters_object.md @@ -0,0 +1,14 @@ +#### Type parameters object + +
    +
    + +Object [WidgetTypeParameters{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L151) describing widget datasource parameters. It has the following properties: + +```javascript + return { + maxDatasources: -1, // Maximum allowed datasources for this widget, -1 - unlimited + maxDataKeys: -1, //Maximum allowed data keys for this widget, -1 - unlimited + dataKeysOptional: false //Whether this widget can be configured with datasources without data keys + } +``` diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index 1dd50841a3..f28590acc9 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -498,10 +498,12 @@ mat-label { color: #0F161D; line-height: normal; font-weight: 500; - padding: 30px 32px 10px; border-bottom: none; margin: 0; } + & > #{$heading} { + padding: 30px 32px 10px; + } } p { @@ -575,6 +577,9 @@ mat-label { margin-bottom: 30px; overflow: hidden; table-layout: fixed; + &.auto { + table-layout: auto; + } & > thead { background-color: #f9fbff; @@ -587,10 +592,12 @@ mat-label { padding: 12px 16px; text-align: left; margin: 0; - word-break: break-word; @media screen and (max-width: 400px) { font-size: 12px; padding: 12px 4px; + code:not([class*=language-]) { + font-size: 12px; + } } } } @@ -608,11 +615,13 @@ mat-label { padding: 12px 16px; text-align: left; margin: 0; - word-break: break-word; color: rgba(15, 22, 29, 0.8); @media screen and (max-width: 400px) { font-size: 12px; padding: 12px 4px; + code:not([class*=language-]) { + font-size: 12px; + } } } } From b0912519e43ff4915da165ff152f319401d40bed Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 18 Oct 2021 16:33:09 +0300 Subject: [PATCH 083/303] RPC v1 and v2 Controllers description --- .../server/controller/BaseController.java | 6 ++ .../controller/EntityQueryController.java | 9 +- .../server/controller/RpcV1Controller.java | 16 ++- .../server/controller/RpcV2Controller.java | 102 ++++++++++++++++-- .../server/common/data/rpc/Rpc.java | 24 +++++ 5 files changed, 138 insertions(+), 19 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 4ec52d5891..0a62409891 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -157,6 +157,8 @@ public abstract class BaseController { public static final String CUSTOMER_ID = "customerId"; public static final String TENANT_ID = "tenantId"; + public static final String DEVICE_ID = "deviceId"; + public static final String RPC_ID = "rpcId"; public static final String ENTITY_ID = "entityId"; public static final String ENTITY_TYPE = "entityType"; @@ -164,6 +166,7 @@ public abstract class BaseController { "The result is wrapped with PageData object that allows you to iterate over result set using pagination. " + "See the 'Model' tab of the Response Class for more details. "; public static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String RPC_ID_PARAM_DESCRIPTION = "A string value representing the rpc id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String DEVICE_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String TENANT_ID_PARAM_DESCRIPTION = "A string value representing the tenant id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; @@ -187,6 +190,7 @@ public abstract class BaseController { protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; + protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name."; protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; @@ -196,6 +200,7 @@ public abstract class BaseController { protected static final String SORT_PROPERTY_DESCRIPTION = "Property of entity to sort by"; protected static final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title"; protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; + protected static final String RPC_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, expirationTime, request, response"; protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; protected static final String DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, transportType, description, isDefault"; protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; @@ -205,6 +210,7 @@ public abstract class BaseController { protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; + protected static final String RPC_STATUS_ALLOWABLE_VALUES = "QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED"; protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP"; protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 7a9e3cf23c..33e819ff00 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -681,8 +681,7 @@ public class EntityQueryController extends BaseController { private static final int MAX_PAGE_SIZE = 100; - @ApiOperation(value = "Count Entities by Query", - notes = ENTITY_COUNT_QUERY_DESCRIPTION) + @ApiOperation(value = "Count Entities by Query", notes = ENTITY_COUNT_QUERY_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/count", method = RequestMethod.POST) @ResponseBody @@ -697,8 +696,7 @@ public class EntityQueryController extends BaseController { } } - @ApiOperation(value = "Find Entity Data by Query", - notes = ENTITY_DATA_QUERY_DESCRIPTION) + @ApiOperation(value = "Find Entity Data by Query", notes = ENTITY_DATA_QUERY_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/find", method = RequestMethod.POST) @ResponseBody @@ -713,8 +711,7 @@ public class EntityQueryController extends BaseController { } } - @ApiOperation(value = "Find Alarms by Query", - notes = ALARM_DATA_QUERY_DESCRIPTION) + @ApiOperation(value = "Find Alarms by Query", notes = ALARM_DATA_QUERY_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarmsQuery/find", method = RequestMethod.POST) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java index 9bece05110..6f23f461b7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -38,17 +40,27 @@ import java.util.UUID; @Slf4j public class RpcV1Controller extends AbstractRpcController { + @ApiOperation(value = "Send one-way RPC request (handleOneWayDeviceRPCRequest)", notes = "Deprecated. See 'Rpc V 2 Controller' instead.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) @ResponseBody - public DeferredResult handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { + public DeferredResult handleOneWayDeviceRPCRequest( + @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + @PathVariable("deviceId") String deviceIdStr, + @ApiParam(value = "A JSON value representing the RPC request.") + @RequestBody String requestBody) throws ThingsboardException { return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT); } + @ApiOperation(value = "Send two-way RPC request (handleTwoWayDeviceRPCRequest)", notes = "Deprecated. See 'Rpc V 2 Controller' instead.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST) @ResponseBody - public DeferredResult handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { + public DeferredResult handleTwoWayDeviceRPCRequest( + @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + @PathVariable("deviceId") String deviceIdStr, + @ApiParam(value = "A JSON value representing the RPC request.") + @RequestBody String requestBody) throws ThingsboardException { return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT); } diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index ae9081c39a..62c9859d1f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -15,6 +15,10 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -52,24 +56,88 @@ import static org.thingsboard.server.common.data.DataConstants.RPC_DELETED; @Slf4j public class RpcV2Controller extends AbstractRpcController { + private static final String RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + + "The RPC call is A JSON that contains the method name ('method'), parameters ('params') and multiple optional fields. " + + "See example below. We will review the properties of the RPC call one-by-one below. " + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"method\": \"setGpio\",\n" + + " \"params\": {\n" + + " \"pin\": 7,\n" + + " \"value\": 1\n" + + " },\n" + + " \"persistent\": false,\n" + + " \"timeout\": 5000\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n### Server-side RPC structure\n" + + "\n" + + "The body of server-side RPC request consists of multiple fields:\n" + + "\n" + + "* **method** - mandatory, name of the method to distinct the RPC calls.\n" + + " For example, \"getCurrentTime\" or \"getWeatherForecast\". The value of the parameter is a string.\n" + + "* **params** - mandatory, parameters used for processing of the request. The value is a JSON. Leave empty JSON \"{}\" if no parameters needed.\n" + + "* **timeout** - optional, value of the processing timeout in milliseconds. The default value is 10000 (10 seconds). The minimum value is 5000 (5 seconds).\n" + + "* **expirationTime** - optional, value of the epoch time (in milliseconds, UTC timezone). Overrides **timeout** if present.\n" + + "* **persistent** - optional, indicates persistent RPC. The default value is \"false\".\n" + + "* **retries** - optional, defines how many times persistent RPC will be re-sent in case of failures on the network and/or device side.\n" + + "* **additionalInfo** - optional, defines metadata for the persistent RPC that will be added to the persistent RPC events."; + + private static final String ONE_WAY_RPC_RESULT = "\n\n### RPC Result\n" + + "In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " + + "the result of this call is either 200 OK if the message was sent to device, or 504 Gateway Timeout if device is offline."; + + private static final String TWO_WAY_RPC_RESULT = "\n\n### RPC Result\n" + + "In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " + + "the result of this call is the response from device, or 504 Gateway Timeout if device is offline."; + + private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT; + + private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT; + + @ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Persistent RPC request was saved to the database or lightweight RPC request was sent to the device."), + @ApiResponse(code = 400, message = "Invalid structure of the request."), + @ApiResponse(code = 401, message = "User is not authorized to send the RPC request. Most likely, User belongs to different Customer or Tenant."), + @ApiResponse(code = 504, message = "Timeout to process the RPC call. Most likely, device is offline."), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) @ResponseBody - public DeferredResult handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { + public DeferredResult handleOneWayDeviceRPCRequest( + @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + @PathVariable("deviceId") String deviceIdStr, + @ApiParam(value = "A JSON value representing the RPC request.") + @RequestBody String requestBody) throws ThingsboardException { return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); } + @ApiOperation(value = "Send two-way RPC request", notes = TWO_WAY_RPC_REQUEST_DESCRIPTION) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Persistent RPC request was saved to the database or lightweight RPC response received."), + @ApiResponse(code = 400, message = "Invalid structure of the request."), + @ApiResponse(code = 401, message = "User is not authorized to send the RPC request. Most likely, User belongs to different Customer or Tenant."), + @ApiResponse(code = 504, message = "Timeout to process the RPC call. Most likely, device is offline."), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST) @ResponseBody - public DeferredResult handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { + public DeferredResult handleTwoWayDeviceRPCRequest( + @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_ID) String deviceIdStr, + @ApiParam(value = "A JSON value representing the RPC request.") + @RequestBody String requestBody) throws ThingsboardException { return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); } + @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET) @ResponseBody - public Rpc getPersistedRpc(@PathVariable("rpcId") String strRpc) throws ThingsboardException { + public Rpc getPersistedRpc( + @ApiParam(value = RPC_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(RPC_ID) String strRpc) throws ThingsboardException { checkParameter("RpcId", strRpc); try { RpcId rpcId = new RpcId(UUID.fromString(strRpc)); @@ -79,16 +147,25 @@ public class RpcV2Controller extends AbstractRpcController { } } + @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET) @ResponseBody - public PageData getPersistedRpcByDevice(@PathVariable("deviceId") String strDeviceId, - @RequestParam int pageSize, - @RequestParam int page, - @RequestParam RpcStatus rpcStatus, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + public PageData getPersistedRpcByDevice( + @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(DEVICE_ID) String strDeviceId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = "Status of the RPC", required = true, allowableValues = RPC_STATUS_ALLOWABLE_VALUES) + @RequestParam RpcStatus rpcStatus, + @ApiParam(value = RPC_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RPC_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("DeviceId", strDeviceId); try { TenantId tenantId = getCurrentUser().getTenantId(); @@ -100,10 +177,13 @@ public class RpcV2Controller extends AbstractRpcController { } } + @ApiOperation(value = "Delete persistent RPC", notes = "Deletes the persistent RPC request.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.DELETE) @ResponseBody - public void deleteResource(@PathVariable("rpcId") String strRpc) throws ThingsboardException { + public void deleteResource( + @ApiParam(value = RPC_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(RPC_ID) String strRpc) throws ThingsboardException { checkParameter("RpcId", strRpc); try { RpcId rpcId = new RpcId(UUID.fromString(strRpc)); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rpc/Rpc.java b/common/data/src/main/java/org/thingsboard/server/common/data/rpc/Rpc.java index 27326087f7..cbe009d1b2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rpc/Rpc.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rpc/Rpc.java @@ -16,6 +16,8 @@ package org.thingsboard.server.common.data.rpc; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; @@ -24,15 +26,24 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.RpcId; import org.thingsboard.server.common.data.id.TenantId; +@ApiModel @Data @EqualsAndHashCode(callSuper = true) public class Rpc extends BaseData implements HasTenantId { + + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", readOnly = true) private TenantId tenantId; + @ApiModelProperty(position = 4, value = "JSON object with Device Id.", readOnly = true) private DeviceId deviceId; + @ApiModelProperty(position = 5, value = "Expiration time of the request.", readOnly = true) private long expirationTime; + @ApiModelProperty(position = 6, value = "The request body that will be used to send message to device.", readOnly = true) private JsonNode request; + @ApiModelProperty(position = 7, value = "The response from the device.", readOnly = true) private JsonNode response; + @ApiModelProperty(position = 8, value = "The current status of the RPC call.", readOnly = true) private RpcStatus status; + @ApiModelProperty(position = 9, value = "Additional info used in the rule engine to process the updates to the RPC state.", readOnly = true) private JsonNode additionalInfo; public Rpc() { @@ -53,4 +64,17 @@ public class Rpc extends BaseData implements HasTenantId { this.status = rpc.getStatus(); this.additionalInfo = rpc.getAdditionalInfo(); } + + @ApiModelProperty(position = 1, value = "JSON object with the rpc Id. Referencing non-existing rpc Id will cause error.") + @Override + public RpcId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the rpc creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + } From c88a44260355fce715338fd25f9b5e78f8636f7a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 18 Oct 2021 19:28:30 +0300 Subject: [PATCH 084/303] Fix default alarm node details builder script. Update rule nodes UI with help resources. --- .../TbAbstractAlarmNodeConfiguration.java | 4 +- .../rulenode/clear_alarm_node_script_fn.md | 68 ++++++++++ .../en_US/rulenode/common_node_script_args.md | 8 ++ .../rulenode/create_alarm_node_script_fn.md | 69 ++++++++++ .../en_US/rulenode/filter_node_script_fn.md | 69 ++++++++++ .../rulenode/generator_node_script_fn.md | 118 ++++++++++++++++++ .../help/en_US/rulenode/log_node_script_fn.md | 37 ++++++ .../en_US/rulenode/switch_node_script_fn.md | 96 ++++++++++++++ .../rulenode/transformation_node_script_fn.md | 18 +-- .../static/rulenode/rulenode-core-config.js | 2 +- 10 files changed, 473 insertions(+), 16 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/clear_alarm_node_script_fn.md create mode 100644 rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/common_node_script_args.md create mode 100644 rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/create_alarm_node_script_fn.md create mode 100644 rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/filter_node_script_fn.md create mode 100644 rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/generator_node_script_fn.md create mode 100644 rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/log_node_script_fn.md create mode 100644 rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/switch_node_script_fn.md diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNodeConfiguration.java index 1cd7c64422..a40089b0be 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNodeConfiguration.java @@ -21,15 +21,13 @@ import lombok.Data; public abstract class TbAbstractAlarmNodeConfiguration { static final String ALARM_DETAILS_BUILD_JS_TEMPLATE = "" + - "//***DO NOT CHANGE THIS LINES***\n" + "var details = {};\n" + "if (metadata.prevAlarmDetails) {\n" + " details = JSON.parse(metadata.prevAlarmDetails);\n" + " //remove prevAlarmDetails from metadata\n" + " delete metadata.prevAlarmDetails;\n" + - " //now metadata is the same as it comes IN this rule node" + + " //now metadata is the same as it comes IN this rule node\n" + "}\n" + - "//***PLACE YOUR CODE BELOW***\n" + "\n" + "\n" + "return details;"; diff --git a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/clear_alarm_node_script_fn.md b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/clear_alarm_node_script_fn.md new file mode 100644 index 0000000000..2191887ebd --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/clear_alarm_node_script_fn.md @@ -0,0 +1,68 @@ +#### Clear alarm details builder function + +
    +
    + +*function Details(msg, metadata, msgType): any* + +JavaScript function generating **Alarm Details** object to update existing one. Used for storing additional parameters inside Alarm.
    +For example you can save attribute name/value pair from Original Message payload or Metadata. + +**Parameters:** + +{% include rulenode/common_node_script_args %} + +**Returns:** + +Should return the object presenting **Alarm Details**. + +Current Alarm Details can be accessed via `metadata.prevAlarmDetails`.
    +**Note** that `metadata.prevAlarmDetails` is a raw String field, and it needs to be converted into object using this construction: + +```javascript +var details = {}; +if (metadata.prevAlarmDetails) { + // remove prevAlarmDetails from metadata + delete metadata.prevAlarmDetails; + details = JSON.parse(metadata.prevAlarmDetails); +} +{:copy-code} +``` + +
    + +##### Examples + +
      +
    • +Take count property from previous Alarm and increment it.
      +Also put temperature attribute from inbound Message payload into Alarm details: +
    • +
    + +```javascript +var details = {temperature: msg.temperature, count: 1}; + +if (metadata.prevAlarmDetails) { + var prevDetails = JSON.parse(metadata.prevAlarmDetails); + // remove prevAlarmDetails from metadata + delete metadata.prevAlarmDetails; + if (prevDetails.count) { + details.count = prevDetails.count + 1; + } +} + +return details; +{:copy-code} +``` + +
    + +More details about Alarms can be found in [this tutorial{:target="_blank"}](${baseUrl}/docs/user-guide/alarms/). + +You can see the real life example, where this node is used, in the next tutorial: + +- [Create and Clear Alarms{:target="_blank"}](${baseUrl}/docs/user-guide/rule-engine-2-0/tutorials/create-clear-alarms/) + +
    +
    diff --git a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/common_node_script_args.md b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/common_node_script_args.md new file mode 100644 index 0000000000..ef53ae37f8 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/common_node_script_args.md @@ -0,0 +1,8 @@ +
      +
    • msg: {[key: string]: any} - is a Message payload key/value object. +
    • +
    • metadata: {[key: string]: string} - is a Message metadata key/value object. +
    • +
    • msgType: string - is a string Message type. See MessageType enum for common used values. +
    • +
    diff --git a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/create_alarm_node_script_fn.md b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/create_alarm_node_script_fn.md new file mode 100644 index 0000000000..66355d5dfc --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/create_alarm_node_script_fn.md @@ -0,0 +1,69 @@ +#### Create alarm details builder function + +
    +
    + +*function Details(msg, metadata, msgType): any* + +JavaScript function generating **Alarm Details** object. Used for storing additional parameters inside Alarm.
    +For example you can save attribute name/value pair from Original Message payload or Metadata. + +**Parameters:** + +{% include rulenode/common_node_script_args %} + +**Returns:** + +Should return the object presenting **Alarm Details**. + +**Optional:** previous Alarm Details can be accessed via `metadata.prevAlarmDetails`.
    +If previous Alarm does not exist, this field will not be present in Metadata. **Note** that `metadata.prevAlarmDetails`
    +is a raw String field, and it needs to be converted into object using this construction: + +```javascript +var details = {}; +if (metadata.prevAlarmDetails) { + // remove prevAlarmDetails from metadata + delete metadata.prevAlarmDetails; + details = JSON.parse(metadata.prevAlarmDetails); +} +{:copy-code} +``` + +
    + +##### Examples + +
      +
    • +Take count property from previous Alarm and increment it.
      +Also put temperature attribute from inbound Message payload into Alarm details: +
    • +
    + +```javascript +var details = {temperature: msg.temperature, count: 1}; + +if (metadata.prevAlarmDetails) { + var prevDetails = JSON.parse(metadata.prevAlarmDetails); + // remove prevAlarmDetails from metadata + delete metadata.prevAlarmDetails; + if (prevDetails.count) { + details.count = prevDetails.count + 1; + } +} + +return details; +{:copy-code} +``` + +
    + +More details about Alarms can be found in [this tutorial{:target="_blank"}](${baseUrl}/docs/user-guide/alarms/). + +You can see the real life example, where this node is used, in the next tutorial: + +- [Create and Clear Alarms{:target="_blank"}](${baseUrl}/docs/user-guide/rule-engine-2-0/tutorials/create-clear-alarms/) + +
    +
    diff --git a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/filter_node_script_fn.md b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/filter_node_script_fn.md new file mode 100644 index 0000000000..16de83ca32 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/filter_node_script_fn.md @@ -0,0 +1,69 @@ +#### Filter message function + +
    +
    + +*function Filter(msg, metadata, msgType): boolean* + +JavaScript function evaluating **true/false** condition on incoming Message. + +**Parameters:** + +{% include rulenode/common_node_script_args %} + +**Returns:** + +Should return `boolean` value. If `true` - send Message via **True** chain, otherwise **False** chain is used. + +
    + +##### Examples + +* Forward all messages with `temperature` value greater than `20` to the **True** chain and all other messages to the **False** chain: + +```javascript +return msg.temperature > 20; +{:copy-code} +``` + +* Forward all messages with type `ATTRIBUTES_UPDATED` to the **True** chain and all other messages to the **False** chain: + +```javascript +if (msgType === 'ATTRIBUTES_UPDATED') { + return true; +} else { + return false; +} +{:copy-code} +``` + +
      +
    • Send message to the True chain if the following conditions are met.
      Message type is POST_TELEMETRY_REQUEST and
      +(device type is vehicle and humidity value is greater than 50 or
      +device type is controller and temperature value is greater than 20 and humidity value is greater than 60).
      +Otherwise send message to the False chain: +
    • +
    + +```javascript +if (msgType === 'POST_TELEMETRY_REQUEST') { + if (metadata.deviceType === 'vehicle') { + return msg.humidity > 50; + } else if (metadata.deviceType === 'controller') { + return msg.temperature > 20 && msg.humidity > 60; + } +} +return false; +{:copy-code} +``` + +
    + +You can see real life example, how to use this node in those tutorials: + +- [Create and Clear Alarms{:target="_blank"}](${baseUrl}/docs/user-guide/rule-engine-2-0/tutorials/create-clear-alarms/#node-a-filter-script) +- [Reply to RPC Calls{:target="_blank"}](${baseUrl}/docs/user-guide/rule-engine-2-0/tutorials/rpc-reply-tutorial#add-filter-script-node) + +
    +
    + diff --git a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/generator_node_script_fn.md b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/generator_node_script_fn.md new file mode 100644 index 0000000000..b3f5bcd059 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/generator_node_script_fn.md @@ -0,0 +1,118 @@ +#### Message generator function + +
    +
    + +*function Generate(prevMsg, prevMetadata, prevMsgType): {msg: object, metadata: object, msgType: string}* + +JavaScript function generating new message using previous Message payload, Metadata and Message type as input arguments. + +**Parameters:** + +
      +
    • prevMsg: {[key: string]: any} - is a previously generated Message payload key/value object. +
    • +
    • prevMetadata: {[key: string]: string} - is a previously generated Message metadata key/value object. +
    • +
    • prevMsgType: string - is a previously generated string Message type. See MessageType enum for common used values. +
    • +
    + +**Returns:** + +Should return the object with the following structure: + +```javascript +{ + msg?: {[key: string]: any}, + metadata?: {[key: string]: string}, + msgType?: string +} +``` + +All fields in resulting object are optional and will be taken from previously generated Message if not specified. + +
    + +##### Examples + +* Generate message of type `POST_TELEMETRY_REQUEST` with random `temperature` value from `18` to `32`: + +```javascript +var temperature = 18 + Math.random() * 14; +// Round to at most 2 decimal places (optional) +temperature = Math.round( temperature * 100 ) / 100; +var msg = { temperature: temperature }; +var metadata = {}; +var msgType = "POST_TELEMETRY_REQUEST"; + +return { msg: msg, metadata: metadata, msgType: msgType }; +{:copy-code} +``` + + +
      +
    • +Generate message of type POST_TELEMETRY_REQUEST with temp value 42, +humidity value 77
      +and metadata with field data having value 40: +
    • +
    + +```javascript +var msg = { temp: 42, humidity: 77 }; +var metadata = { data: 40 }; +var msgType = "POST_TELEMETRY_REQUEST"; + +return { msg: msg, metadata: metadata, msgType: msgType }; +{:copy-code} +``` + +
      +
    • +Generate message of type POST_TELEMETRY_REQUEST with temperature value
      +increasing and decreasing linearly in the range from 18 to 32: +
    • +
    + +```javascript +var lower = 18; +var upper = 32; +var isDecrement = 'false'; +var temperature = lower; + +// Get previous values + +if (typeof prevMetadata !== 'undefined' && + typeof prevMetadata.isDecrement !== 'undefined') { + isDecrement = prevMetadata.isDecrement; +} +if (typeof prevMsg !== 'undefined' && + typeof prevMsg.temperature !== 'undefined') { + temperature = prevMsg.temperature; +} + +if (isDecrement === 'true') { + temperature--; + if (temperature <= lower) { + isDecrement = 'false'; + temperature = lower; + } +} else { + temperature++; + if (temperature >= upper) { + isDecrement = 'true'; + temperature = upper; + } +} + +var msg = { temperature: temperature }; +var metadata = { isDecrement: isDecrement }; +var msgType = "POST_TELEMETRY_REQUEST"; + +return { msg: msg, metadata: metadata, msgType: msgType }; +{:copy-code} +``` + +
    +
    diff --git a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/log_node_script_fn.md b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/log_node_script_fn.md new file mode 100644 index 0000000000..c5cf6bcd34 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/log_node_script_fn.md @@ -0,0 +1,37 @@ +#### Message to string function + +
    +
    + +*function toString(msg, metadata, msgType): string* + +JavaScript function transforming incoming Message to String for further logging to the server log file. + +**Parameters:** + +{% include rulenode/common_node_script_args %} + +**Returns:** + +Should return `string` value used for logging to the server log file. + +
    + +##### Examples + +* Create string message containing incoming message and incoming metadata values: + +```javascript +return 'Incoming message:\n' + JSON.stringify(msg) + + '\nIncoming metadata:\n' + JSON.stringify(metadata); +{:copy-code} +``` + +
    + +You can see real life example, how to use this node in this tutorial: + +- [Reply to RPC Calls{:target="_blank"}](${baseUrl}/docs/user-guide/rule-engine-2-0/tutorials/rpc-reply-tutorial#log-unknown-request) + +
    +
    diff --git a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/switch_node_script_fn.md b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/switch_node_script_fn.md new file mode 100644 index 0000000000..1f6a1067b8 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/switch_node_script_fn.md @@ -0,0 +1,96 @@ +#### Switch message function + +
    +
    + +*function Switch(msg, metadata, msgType): string[]* + +JavaScript function computing **an array of next Relation names** for incoming Message. + +**Parameters:** + +{% include rulenode/common_node_script_args %} + +**Returns:** + +Should return an array of `string` values presenting **next Relation names** where Message should be routed.
    +If returned array is empty - message will not be routed to any Node and discarded. + +
    + +##### Examples + +
      +
    • +Forward all messages with temperature value greater than 30 to the 'High temperature' chain,
      +with temperature value lower than 20 to the 'Low temperature' chain and all other messages
      +to the 'Normal temperature' chain: +
    • +
    + +```javascript +if (msg.temperature > 30) { + return ['High temperature']; +} else if (msg.temperature < 20) { + return ['Low temperature']; +} else { + return ['Normal temperature']; +} +{:copy-code} +``` + +
      +
    • + For messages with type POST_TELEMETRY_REQUEST: +
        +
      • + if temperature value lower than 18 forward to the 'Low temperature telemetry' chain, +
      • +
      • + otherwise to the 'Normal temperature telemetry' chain. +
      • +
      + For messages with type POST_ATTRIBUTES_REQUEST:
      +
        +
      • + if currentState value is IDLE forward to the 'Idle State' and 'Update State Attribute' chains, +
      • +
      • + if currentState value is RUNNING forward to the 'Running State' and 'Update State Attribute' chains, +
      • +
      • + otherwise to the 'Unknown State' chain. +
      • +
      + For all other message types - discard the message (do not route to any Node). +
    • +
    + +```javascript +if (msgType === 'POST_TELEMETRY_REQUEST') { + if (msg.temperature < 18) { + return ['Low Temperature Telemetry']; + } else { + return ['Normal Temperature Telemetry']; + } +} else if (msgType === 'POST_ATTRIBUTES_REQUEST') { + if (msg.currentState === 'IDLE') { + return ['Idle State', 'Update State Attribute']; + } else if (msg.currentState === 'RUNNING') { + return ['Running State', 'Update State Attribute']; + } else { + return ['Unknown State']; + } +} +return []; +{:copy-code} +``` + +
    + +You can see real life example, how to use this node in this tutorial: + +- [Data function based on telemetry from 2 devices{:target="_blank"}](${baseUrl}/docs/user-guide/rule-engine-2-0/tutorials/function-based-on-telemetry-from-two-devices#delta-temperature-rule-chain) + +
    +
    diff --git a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/transformation_node_script_fn.md b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/transformation_node_script_fn.md index 7ac7722260..ae2f1a0ffa 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/transformation_node_script_fn.md +++ b/rule-engine/rule-engine-components/src/main/resources/public/assets/help/en_US/rulenode/transformation_node_script_fn.md @@ -3,20 +3,13 @@

    -*function (msg, metadata msgType): {msg: object, metadata: object, msgType: string}* +*function Transform(msg, metadata, msgType): {msg: object, metadata: object, msgType: string}* JavaScript function transforming input Message payload, Metadata or Message type. **Parameters:** -
      -
    • msg: {[key: string]: any} - is a Message payload key/value object. -
    • -
    • metadata: {[key: string]: string} - is a Message metadata key/value object. -
    • -
    • msgType: string - is a string Message type. See MessageType enum for common used values. -
    • -
    +{% include rulenode/common_node_script_args %} **Returns:** @@ -47,8 +40,6 @@ return { msgType: 'CUSTOM_REQUEST' };
  • Change message type to CUSTOM_UPDATE,
    add additional attribute version into payload with value v1.1,
    change sensorType attribute value in Metadata to roomTemp:
  • -The following transform function will perform all necessary modifications: - ```javascript var newType = "CUSTOM_UPDATE"; msg.version = "v1.1"; @@ -57,9 +48,12 @@ return {msg: msg, metadata: metadata, msgType: newType}; {:copy-code} ``` +
    + You can see real life example, how to use this node in those tutorials: - [Transform incoming telemetry{:target="_blank"}](${baseUrl}/docs/user-guide/rule-engine-2-0/tutorials/transform-incoming-telemetry/) - [Reply to RPC Calls{:target="_blank"}](${baseUrl}/docs/user-guide/rule-engine-2-0/tutorials/rpc-reply-tutorial#add-transform-script-node) - +
    +
    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 59f54df936..fe4b5482bf 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 @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
    "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
    tb.rulenode.notify-device-hint
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
    \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
    \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
    \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
    \n \n \n \n
    \n \n
    \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
    \n
    \n
    \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
    \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
    tb.rulenode.create-entity-if-not-exists-hint
    \n
    \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
    tb.rulenode.remove-current-relations-hint
    \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
    tb.rulenode.change-originator-to-related-entity-hint
    \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
    \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
    tb.rulenode.use-metadata-period-in-seconds-patterns-hint
    \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
    \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
    tb.rulenode.delete-relation-hint
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
    \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
    \n \n \n \n
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,z=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var _,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(_||(_={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
    \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
    \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
    \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
    \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
    \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
    \n
    \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
    \n
    \n
    \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
    \n
    \n \n
    \n \n
    \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
    \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
    \n
    relation.relation-type
    \n \n \n
    device.device-types
    \n \n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
    \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
    \n
    relation.relation-filters
    \n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-message-types-found\n
    \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
    \n
    \n
    \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
    \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
    \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
    {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
    \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
    \n
    \n
    \n
    \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
    \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
    \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
    \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
    \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
    \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
    tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
    \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
    \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
    \n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
    \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
    \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(_),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
    \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
    \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
    \n
    \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
    \n
    \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
    \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
    \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
    \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
    \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
    \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
    \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
    \n
    \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
    \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
    \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
    \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
    \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
    \n
    \n
    \n
    \n
    \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
    \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
    \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
    \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
    tb.rulenode.separator-hint
    \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
    tb.rulenode.separator-hint
    \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
    tb.rulenode.check-all-keys-hint
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
    \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
    tb.rulenode.check-relation-hint
    \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
    \n \n \n \n \n
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
    \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
    \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n
    \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
    \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
    \n \n \n \n
    \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
    \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-alarm-status-matching\n
    \n
    \n
    \n
    \n
    \n \n
    \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
    \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=z,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(z.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(z.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
    \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-entity-details-matching\n
    \n
    \n
    \n
    \n
    \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
    tb.rulenode.add-to-metadata-hint
    \n
    \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
    \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
    tb.rulenode.tell-failure-if-absent-hint
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
    \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
    tb.rulenode.tell-failure-if-absent-hint
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
    \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
    \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
    \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
    tb.rulenode.use-metadata-interval-patterns-hint
    \n
    \n
    \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
    \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
    \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
    \n
    \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
    \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),_e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
    \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
    \n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
    \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[_e,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[_e,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,ze,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=ze,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=_e,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
    "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
    tb.rulenode.notify-device-hint
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
    \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
    \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
    \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
    \n \n \n \n
    \n \n
    \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
    \n
    \n
    \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
    \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
    tb.rulenode.create-entity-if-not-exists-hint
    \n
    \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
    tb.rulenode.remove-current-relations-hint
    \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
    tb.rulenode.change-originator-to-related-entity-hint
    \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
    \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
    tb.rulenode.use-metadata-period-in-seconds-patterns-hint
    \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
    \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
    tb.rulenode.delete-relation-hint
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
    \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
    \n \n \n \n
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
    \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
    \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
    \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
    \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
    \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
    \n
    \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
    \n
    \n
    \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
    \n
    \n \n
    \n \n
    \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
    \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
    \n
    relation.relation-type
    \n \n \n
    device.device-types
    \n \n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
    \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
    \n
    relation.relation-filters
    \n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-message-types-found\n
    \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
    \n
    \n
    \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
    \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
    \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
    {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
    \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
    \n
    \n
    \n
    \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
    \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
    \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
    \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
    \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
    \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
    tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
    \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
    \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
    \n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
    \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
    \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
    \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
    \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
    \n
    \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
    \n
    \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
    \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
    \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
    \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
    \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
    \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
    \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
    \n
    \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
    \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
    \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
    \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
    \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
    \n
    \n
    \n
    \n
    \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
    \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
    \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
    \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
    tb.rulenode.separator-hint
    \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
    tb.rulenode.separator-hint
    \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
    tb.rulenode.check-all-keys-hint
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
    \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
    tb.rulenode.check-relation-hint
    \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
    \n \n \n \n \n
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
    \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
    \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n
    \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
    \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
    \n \n \n \n
    \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
    \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-alarm-status-matching\n
    \n
    \n
    \n
    \n
    \n \n
    \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
    \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
    \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-entity-details-matching\n
    \n
    \n
    \n
    \n
    \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
    tb.rulenode.add-to-metadata-hint
    \n
    \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
    \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
    tb.rulenode.tell-failure-if-absent-hint
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
    \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
    tb.rulenode.tell-failure-if-absent-hint
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
    \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
    \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
    \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
    tb.rulenode.use-metadata-interval-patterns-hint
    \n
    \n
    \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
    \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
    \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
    \n
    \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
    \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
    \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
    \n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
    \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 3bace7756bb7426c534f36d3dff9fe4b46f1b407 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 19 Oct 2021 13:13:05 +0300 Subject: [PATCH 085/303] Lwm2m fix bug if model == null --- .../lwm2m/server/LwM2mVersionedModelProvider.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java index 9448d9c0a4..ad31c674c3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java @@ -95,7 +95,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { if (objectModel != null) return objectModel.resources.get(resourceId); else - log.trace("TbResources (Object model) with id [{}/0/{}] not found on the server", objectId, resourceId); + log.trace("TbResources (Object model) with id [{}/0/{}] not found on the server.", objectId, resourceId); return null; } catch (Exception e) { log.error("", e); @@ -128,14 +128,17 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { private ObjectModel getObjectModelDynamic(Integer objectId, String version) { String key = getKeyIdVer(objectId, version); ObjectModel objectModel = models.get(tenantId).get(key); - if (objectModel == null) { modelsLock.lock(); try { objectModel = models.get(tenantId).get(key); if (objectModel == null) { objectModel = getObjectModel(key); + } + if (objectModel != null) { models.get(tenantId).put(key, objectModel); + } else { + log.error("Object model with id [{}] version [{}] not found on the server.", objectId, version); } } finally { modelsLock.unlock(); From 7bcc147d1cfbd437ea666c4264edce8b4f32e78c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 19 Oct 2021 14:44:41 +0300 Subject: [PATCH 086/303] Lwm2m fix bug if model == null add log to thingsboard --- .../downlink/DefaultLwM2mDownlinkMsgHandler.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 64d42f001e..ccfcd57163 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -186,6 +186,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } sendSimpleRequest(client, downlink, request.getTimeout(), callback); } + else { + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); + } } @Override @@ -271,10 +274,15 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im **/ Collection resources = client.getNewResourceForInstance(request.getVersionedId(), request.getValue(), modelProvider, this.converter); ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), modelProvider); - ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : convertResourceModelTypeToContentFormat(client, resourceModelWrite.type); - WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), - resultIds.getObjectInstanceId(), resources); - sendSimpleRequest(client, downlink, request.getTimeout(), callback); + if (resourceModelWrite != null) { + ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : convertResourceModelTypeToContentFormat(client, resourceModelWrite.type); + WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), + resultIds.getObjectInstanceId(), resources); + sendSimpleRequest(client, downlink, request.getTimeout(), callback); + } + else { + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); + } } else if (resultIds.isObjectInstance()) { /* * params = "{\"id\":0,\"resources\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" From 546bded3633e8f7d0f1715c6e3d3f182919b56d7 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 19 Oct 2021 15:15:39 +0300 Subject: [PATCH 087/303] Rule Chain Controller description --- .../server/controller/BaseController.java | 4 + .../server/controller/RpcV2Controller.java | 10 +- .../controller/RuleChainController.java | 103 ++++++++++++++++-- .../rule/DefaultRuleChainCreateRequest.java | 4 + .../common/data/rule/NodeConnectionInfo.java | 6 + .../server/common/data/rule/RuleChain.java | 26 +++++ .../data/rule/RuleChainConnectionInfo.java | 7 ++ .../common/data/rule/RuleChainData.java | 5 + .../common/data/rule/RuleChainMetaData.java | 8 ++ .../server/common/data/rule/RuleNode.java | 29 +++++ 10 files changed, 185 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 0a62409891..a49b06cab8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -187,11 +187,13 @@ public abstract class BaseController { protected static final String DEVICE_TYPE_DESCRIPTION = "Device type as the name of the device profile"; protected static final String ASSET_TYPE_DESCRIPTION = "Asset type"; protected static final String EDGE_TYPE_DESCRIPTION = "A string value representing the edge type. For example, 'default'"; + protected static final String RULE_CHAIN_TYPE_DESCRIPTION = "Rule chain type (CORE or EDGE)"; protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; + protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name."; protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name."; protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name."; @@ -207,10 +209,12 @@ public abstract class BaseController { protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; + protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root"; protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected static final String RPC_STATUS_ALLOWABLE_VALUES = "QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED"; + protected static final String RULE_CHAIN_TYPES_ALLOWABLE_VALUES = "CORE, EDGE"; protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP"; protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index 62c9859d1f..391f55f4fc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -91,9 +91,9 @@ public class RpcV2Controller extends AbstractRpcController { "In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " + "the result of this call is the response from device, or 504 Gateway Timeout if device is offline."; - private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT; + private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT + TENANT_AND_USER_AUTHORITY_PARAGRAPH; - private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT; + private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_AND_USER_AUTHORITY_PARAGRAPH; @ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION) @ApiResponses(value = { @@ -131,7 +131,7 @@ public class RpcV2Controller extends AbstractRpcController { return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); } - @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call.") + @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call." + TENANT_AND_USER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET) @ResponseBody @@ -147,7 +147,7 @@ public class RpcV2Controller extends AbstractRpcController { } } - @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination.") + @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_AND_USER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET) @ResponseBody @@ -177,7 +177,7 @@ public class RpcV2Controller extends AbstractRpcController { } } - @ApiOperation(value = "Delete persistent RPC", notes = "Deletes the persistent RPC request.") + @ApiOperation(value = "Delete persistent RPC", notes = "Deletes the persistent RPC request." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.DELETE) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 40cc46ffa1..21a2d8afb2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -95,6 +96,25 @@ public class RuleChainController extends BaseController { private static final ObjectMapper objectMapper = new ObjectMapper(); public static final int TIMEOUT = 20; + private static final String RULE_CHAIN_DESCRIPTION = "The rule chain object is lightweight and contains general information about the rule chain. " + + "List of rule nodes and their connection is stored in a separate 'metadata' object."; + private static final String RULE_CHAIN_METADATA_DESCRIPTION = "The metadata object contains information about the rule nodes and their connections."; + private static final String TEST_JS_FUNCTION = "Execute the JavaScript function and return the result. The format of request: \n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"script\": \"Your JS Function as String\",\n" + + " \"scriptType\": \"One of: update, generate, filter, switch, json, string\",\n" + + " \"argNames\": [\"msg\", \"metadata\", \"type\"],\n" + + " \"msg\": \"{\\\"temperature\\\": 42}\", \n" + + " \"metadata\": {\n" + + " \"deviceName\": \"Device A\",\n" + + " \"deviceType\": \"Thermometer\"\n" + + " },\n" + + " \"msgType\": \"POST_TELEMETRY_REQUEST\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n Expected result JSON contains \"output\" and \"error\"."; + @Autowired private InstallScripts installScripts; @@ -110,10 +130,14 @@ public class RuleChainController extends BaseController { @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled}") private boolean debugPerTenantEnabled; + @ApiOperation(value = "Get Rule Chain (getRuleChainById)", + notes = "Fetch the Rule Chain object based on the provided Rule Chain Id. " + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET) @ResponseBody - public RuleChain getRuleChainById(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + public RuleChain getRuleChainById( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { checkParameter(RULE_CHAIN_ID, strRuleChainId); try { RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); @@ -123,10 +147,14 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Get Rule Chain (getRuleChainById)", + notes = "Fetch the Rule Chain Metadata object based on the provided Rule Chain Id. " + RULE_CHAIN_METADATA_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/{ruleChainId}/metadata", method = RequestMethod.GET) @ResponseBody - public RuleChainMetaData getRuleChainMetaData(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + public RuleChainMetaData getRuleChainMetaData( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { checkParameter(RULE_CHAIN_ID, strRuleChainId); try { RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); @@ -137,11 +165,18 @@ public class RuleChainController extends BaseController { } } - + @ApiOperation(value = "Create Or Update Rule Chain (saveRuleChain)", + notes = "Create or update the Rule Chain. When creating Rule Chain, platform generates Rule Chain Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created Rule Chain Id will be present in the response. " + + "Specify existing Rule Chain id to update the rule chain. " + + "Referencing non-existing rule chain Id will cause 'Not Found' error." + + "\n\n" + RULE_CHAIN_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain", method = RequestMethod.POST) @ResponseBody - public RuleChain saveRuleChain(@RequestBody RuleChain ruleChain) throws ThingsboardException { + public RuleChain saveRuleChain( + @ApiParam(value = "A JSON value representing the rule chain.") + @RequestBody RuleChain ruleChain) throws ThingsboardException { try { boolean created = ruleChain.getId() == null; ruleChain.setTenantId(getCurrentUser().getTenantId()); @@ -175,10 +210,15 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Create Default Rule Chain", + notes = "Create rule chain from template, based on the specified name in the request. " + + "Creates the rule chain based on the template that is used to create root rule chain. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/device/default", method = RequestMethod.POST) @ResponseBody - public RuleChain saveRuleChain(@RequestBody DefaultRuleChainCreateRequest request) throws ThingsboardException { + public RuleChain saveRuleChain( + @ApiParam(value = "A JSON value representing the request.") + @RequestBody DefaultRuleChainCreateRequest request) throws ThingsboardException { try { checkNotNull(request); checkParameter(request.getName(), "name"); @@ -198,10 +238,14 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Set Root Rule Chain (setRootRuleChain)", + notes = "Makes the rule chain to be root rule chain. Updates previous root rule chain as well. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/{ruleChainId}/root", method = RequestMethod.POST) @ResponseBody - public RuleChain setRootRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + public RuleChain setRootRuleChain( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { checkParameter(RULE_CHAIN_ID, strRuleChainId); try { RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); @@ -237,10 +281,14 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Update Rule Chain Metadata", + notes = "Updates the rule chain metadata. " + RULE_CHAIN_METADATA_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/metadata", method = RequestMethod.POST) @ResponseBody - public RuleChainMetaData saveRuleChainMetaData(@RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException { + public RuleChainMetaData saveRuleChainMetaData( + @ApiParam(value = "A JSON value representing the rule chain metadata.") + @RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException { try { TenantId tenantId = getTenantId(); if (debugPerTenantEnabled) { @@ -278,15 +326,24 @@ public class RuleChainController extends BaseController { } } + + @ApiOperation(value = "Get Rule Chains (getRuleChains)", + notes = "Returns a page of Rule Chains owned by tenant. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getRuleChains( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = RULE_CHAIN_TYPE_DESCRIPTION, allowableValues = RULE_CHAIN_TYPES_ALLOWABLE_VALUES) @RequestParam(value = "type", required = false) String typeStr, + @ApiParam(value = RULE_CHAIN_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); @@ -301,10 +358,14 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Delete rule chain (deleteRuleChain)", + notes = "Deletes the rule chain. Referencing non-existing rule chain Id will cause an error. Referencing rule chain that is used in the device profiles will cause an error.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + public void deleteRuleChain( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { checkParameter(RULE_CHAIN_ID, strRuleChainId); try { RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); @@ -347,10 +408,15 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Get latest input message (getLatestRuleNodeDebugInput)", + notes = "Gets the input message from the debug events for specified Rule Chain Id. " + + "Referencing non-existing rule chain Id will cause an error. ") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleNode/{ruleNodeId}/debugIn", method = RequestMethod.GET) @ResponseBody - public JsonNode getLatestRuleNodeDebugInput(@PathVariable(RULE_NODE_ID) String strRuleNodeId) throws ThingsboardException { + public JsonNode getLatestRuleNodeDebugInput( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_NODE_ID) String strRuleNodeId) throws ThingsboardException { checkParameter(RULE_NODE_ID, strRuleNodeId); try { RuleNodeId ruleNodeId = new RuleNodeId(toUUID(strRuleNodeId)); @@ -373,10 +439,15 @@ public class RuleChainController extends BaseController { } } + + @ApiOperation(value = "Test JavaScript function", + notes = TEST_JS_FUNCTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/testScript", method = RequestMethod.POST) @ResponseBody - public JsonNode testScript(@RequestBody JsonNode inputParams) throws ThingsboardException { + public JsonNode testScript( + @ApiParam(value = "Test JS request. See API call description above.") + @RequestBody JsonNode inputParams) throws ThingsboardException { try { String script = inputParams.get("script").asText(); String scriptType = inputParams.get("scriptType").asText(); @@ -436,10 +507,13 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Export Rule Chains", notes = "Exports all tenant rule chains as one JSON." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChains/export", params = {"limit"}, method = RequestMethod.GET) @ResponseBody - public RuleChainData exportRuleChains(@RequestParam("limit") int limit) throws ThingsboardException { + public RuleChainData exportRuleChains( + @ApiParam(value = "A limit of rule chains to export.", required = true) + @RequestParam("limit") int limit) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); PageLink pageLink = new PageLink(limit); @@ -449,10 +523,15 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Import Rule Chains", notes = "Imports all tenant rule chains as one JSON." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST) @ResponseBody - public void importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { + public void importRuleChains( + @ApiParam(value = "A JSON value representing the rule chains.") + @RequestBody RuleChainData ruleChainData, + @ApiParam(value = "Enables overwrite for existing rule chains with the same name.") + @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); List importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/DefaultRuleChainCreateRequest.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/DefaultRuleChainCreateRequest.java index cbabe39938..e9a7bba35d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/DefaultRuleChainCreateRequest.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/DefaultRuleChainCreateRequest.java @@ -15,17 +15,21 @@ */ package org.thingsboard.server.common.data.rule; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.extern.slf4j.Slf4j; import java.io.Serializable; +@ApiModel @Data @Slf4j public class DefaultRuleChainCreateRequest implements Serializable { private static final long serialVersionUID = 5600333716030561537L; + @ApiModelProperty(position = 1, required = true, value = "Name of the new rule chain", example = "Root Rule Chain") private String name; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/NodeConnectionInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/NodeConnectionInfo.java index 119af4ce4f..981fbb85dd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/NodeConnectionInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/NodeConnectionInfo.java @@ -15,14 +15,20 @@ */ package org.thingsboard.server.common.data.rule; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * Created by ashvayka on 21.03.18. */ +@ApiModel @Data public class NodeConnectionInfo { + @ApiModelProperty(position = 1, required = true, value = "Index of rule node in the 'nodes' array of the RuleChainMetaData. Indicates the 'from' part of the connection.") private int fromIndex; + @ApiModelProperty(position = 2, required = true, value = "Index of rule node in the 'nodes' array of the RuleChainMetaData. Indicates the 'to' part of the connection.") private int toIndex; + @ApiModelProperty(position = 3, required = true, value = "Type of the relation. Typically indicated the result of processing by the 'from' rule node. For example, 'Success' or 'Failure'") private String type; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java index da84f15427..6cfa13a867 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java @@ -17,6 +17,8 @@ package org.thingsboard.server.common.data.rule; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -28,6 +30,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.validation.NoXss; +@ApiModel @Data @EqualsAndHashCode(callSuper = true) @Slf4j @@ -35,13 +38,20 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo im private static final long serialVersionUID = -5656679015121935465L; + @ApiModelProperty(position = 3, required = true, value = "JSON object with Tenant Id.", readOnly = true) private TenantId tenantId; @NoXss + @ApiModelProperty(position = 4, required = true, value = "Rule Chain name", example = "Humidity data processing") private String name; + @ApiModelProperty(position = 5, value = "Rule Chain type. 'EDGE' rule chains are processing messages on the edge devices only.", example = "A4B72CCDFF33") private RuleChainType type; + @ApiModelProperty(position = 6, value = "JSON object with Rule Chain Id. Pointer to the first rule node that should receive all messages pushed to this rule chain.") private RuleNodeId firstRuleNodeId; + @ApiModelProperty(position = 7, value = "Indicates root rule chain. The root rule chain process messages from all devices and entities by default. User may configure default rule chain per device profile.") private boolean root; + @ApiModelProperty(position = 8, value = "Reserved for future usage.") private boolean debugMode; + @ApiModelProperty(position = 9, value = "Reserved for future usage. The actual list of rule nodes and their relations is stored in the database separately.") private transient JsonNode configuration; @JsonIgnore @@ -75,6 +85,21 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo im return name; } + @ApiModelProperty(position = 1, value = "JSON object with the Rule Chain Id. " + + "Specify this field to update the Rule Chain. " + + "Referencing non-existing Rule Chain Id will cause error. " + + "Omit this field to create new rule chain." ) + @Override + public RuleChainId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the rule chain creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + public JsonNode getConfiguration() { return SearchTextBasedWithAdditionalInfo.getJson(() -> configuration, () -> configurationBytes); } @@ -82,4 +107,5 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo im public void setConfiguration(JsonNode data) { setJson(data, json -> this.configuration = json, bytes -> this.configurationBytes = bytes); } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainConnectionInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainConnectionInfo.java index 6b1646b8f1..68efc565be 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainConnectionInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainConnectionInfo.java @@ -16,16 +16,23 @@ package org.thingsboard.server.common.data.rule; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.RuleChainId; /** * Created by ashvayka on 21.03.18. */ +@ApiModel @Data public class RuleChainConnectionInfo { + @ApiModelProperty(position = 1, required = true, value = "Index of rule node in the 'nodes' array of the RuleChainMetaData. Indicates the 'from' part of the connection.") private int fromIndex; + @ApiModelProperty(position = 2, required = true, value = "JSON object with the Rule Chain Id.") private RuleChainId targetRuleChainId; + @ApiModelProperty(position = 3, required = true, value = "JSON object with the additional information about the connection.") private JsonNode additionalInfo; + @ApiModelProperty(position = 4, required = true, value = "Type of the relation. Typically indicated the result of processing by the 'from' rule node. For example, 'Success' or 'Failure'") private String type; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainData.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainData.java index 912120e0ad..8df7f24eba 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainData.java @@ -15,13 +15,18 @@ */ package org.thingsboard.server.common.data.rule; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.List; +@ApiModel @Data public class RuleChainData { + @ApiModelProperty(position = 1, required = true, value = "List of the Rule Chain objects.", readOnly = true) List ruleChains; + @ApiModelProperty(position = 2, required = true, value = "List of the Rule Chain metadata objects.", readOnly = true) List metadata; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java index 33a4aaa6bb..0b069d7889 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java @@ -16,6 +16,8 @@ package org.thingsboard.server.common.data.rule; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.RuleChainId; @@ -25,17 +27,23 @@ import java.util.List; /** * Created by igor on 3/13/18. */ +@ApiModel @Data public class RuleChainMetaData { + @ApiModelProperty(position = 1, required = true, value = "JSON object with Rule Chain Id.", readOnly = true) private RuleChainId ruleChainId; + @ApiModelProperty(position = 2, required = true, value = "Index of the first rule node in the 'nodes' list") private Integer firstNodeIndex; + @ApiModelProperty(position = 3, required = true, value = "List of rule node JSON objects") private List nodes; + @ApiModelProperty(position = 4, required = true, value = "List of JSON objects that represent connections between rule nodes") private List connections; + @ApiModelProperty(position = 5, required = true, value = "List of JSON objects that represent connections between rule nodes and other rule chains.") private List ruleChainConnections; public void addConnectionInfo(int fromIndex, int toIndex, String type) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java index 6d88ad6adc..a44595dcfa 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java @@ -17,6 +17,8 @@ package org.thingsboard.server.common.data.rule; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -25,6 +27,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +@ApiModel @Data @EqualsAndHashCode(callSuper = true) @Slf4j @@ -32,10 +35,15 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo impl private static final long serialVersionUID = -5656679015121235465L; + @ApiModelProperty(position = 3, value = "JSON object with the Rule Chain Id. ", readOnly = true) private RuleChainId ruleChainId; + @ApiModelProperty(position = 4, value = "Full Java Class Name of the rule node implementation. ", example = "com.mycompany.iot.rule.engine.ProcessingNode") private String type; + @ApiModelProperty(position = 5, value = "User defined name of the rule node. Used on UI and for logging. ", example = "Process sensor reading") private String name; + @ApiModelProperty(position = 6, value = "Enable/disable debug. ", example = "false") private boolean debugMode; + @ApiModelProperty(position = 7, value = "JSON with the rule node configuration. Structure depends on the rule node implementation.", dataType = "com.fasterxml.jackson.databind.JsonNode") private transient JsonNode configuration; @JsonIgnore private byte[] configurationBytes; @@ -75,4 +83,25 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo impl setJson(data, json -> this.configuration = json, bytes -> this.configurationBytes = bytes); } + @ApiModelProperty(position = 1, value = "JSON object with the Rule Node Id. " + + "Specify this field to update the Rule Node. " + + "Referencing non-existing Rule Node Id will cause error. " + + "Omit this field to create new rule node." ) + @Override + public RuleNodeId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the rule node creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + + @ApiModelProperty(position = 8, value = "Additional parameters of the rule node. Contains 'layoutX' and 'layoutY' properties for visualization.", dataType = "com.fasterxml.jackson.databind.JsonNode") + @Override + public JsonNode getAdditionalInfo() { + return super.getAdditionalInfo(); + } + } From 45d49153e253d10ec1cc63d4467fed8632c43d1f Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 19 Oct 2021 18:12:43 +0300 Subject: [PATCH 088/303] Tenant and Tenant Profile Controllers --- .../server/controller/BaseController.java | 9 +++ .../server/controller/DeviceController.java | 2 +- .../server/controller/TenantController.java | 72 +++++++++++++---- .../controller/TenantProfileController.java | 76 ++++++++++++++---- .../server/common/data/Customer.java | 76 +++++++++++++++++- .../server/common/data/DeviceProfileInfo.java | 5 ++ .../server/common/data/EntityInfo.java | 5 ++ .../server/common/data/Tenant.java | 78 +++++++++++++++++++ .../server/common/data/TenantInfo.java | 5 +- .../server/common/data/TenantProfile.java | 26 +++++++ .../DefaultTenantProfileConfiguration.java | 2 + .../profile/TenantProfileConfiguration.java | 1 + .../tenant/profile/TenantProfileData.java | 4 + 13 files changed, 327 insertions(+), 34 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index a49b06cab8..542928b8bf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -169,6 +169,7 @@ public abstract class BaseController { public static final String RPC_ID_PARAM_DESCRIPTION = "A string value representing the rpc id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String DEVICE_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String TENANT_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the tenant profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String TENANT_ID_PARAM_DESCRIPTION = "A string value representing the tenant id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String EDGE_ID_PARAM_DESCRIPTION = "A string value representing the edge id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; @@ -179,6 +180,8 @@ public abstract class BaseController { public static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; + protected static final String SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority."; protected static final String TENANT_AND_USER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; @@ -193,6 +196,8 @@ public abstract class BaseController { protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; + protected static final String TENANT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant name."; + protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant profile name."; protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name."; protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name."; protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; @@ -204,6 +209,10 @@ public abstract class BaseController { protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; protected static final String RPC_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, expirationTime, request, response"; protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; + protected static final String TENANT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, state, city, address, address2, zip, phone, email"; + protected static final String TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault"; + protected static final String TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; + protected static final String TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, tenantProfileName, title, email, country, state, city, address, address2, zip, phone, email"; protected static final String DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, transportType, description, isDefault"; protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; 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 a6e744d8a9..0bbf1a6c8b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -373,7 +373,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get Tenant Devices (getTenantDevices)", notes = "Returns a page of devices owned by tenant. " + - PAGE_DATA_PARAMETERS) + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/devices", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index 3459d61c8b..c3e2492632 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -16,6 +16,8 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.node.ObjectNode; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -47,21 +49,26 @@ import org.thingsboard.server.service.security.permission.Resource; @Slf4j public class TenantController extends BaseController { + private static final String TENANT_INFO_DESCRIPTION = "The Tenant Info object extends regular Tenant object and includes Tenant Profile name. "; @Autowired private InstallScripts installScripts; @Autowired private TenantService tenantService; + @ApiOperation(value = "Get Tenant (getTenantById)", + notes = "Fetch the Tenant object based on the provided Tenant Id. " + SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.GET) @ResponseBody - public Tenant getTenantById(@PathVariable("tenantId") String strTenantId) throws ThingsboardException { + public Tenant getTenantById( + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION) + @PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException { checkParameter(TENANT_ID, strTenantId); try { TenantId tenantId = new TenantId(toUUID(strTenantId)); Tenant tenant = checkTenantId(tenantId, Operation.READ); - if(!tenant.getAdditionalInfo().isNull()) { + if (!tenant.getAdditionalInfo().isNull()) { processDashboardIdFromAdditionalInfo((ObjectNode) tenant.getAdditionalInfo(), HOME_DASHBOARD); } return tenant; @@ -70,10 +77,15 @@ public class TenantController extends BaseController { } } + @ApiOperation(value = "Get Tenant Info (getTenantInfoById)", + notes = "Fetch the Tenant Info object based on the provided Tenant Id. " + + TENANT_INFO_DESCRIPTION + SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/tenant/info/{tenantId}", method = RequestMethod.GET) @ResponseBody - public TenantInfo getTenantInfoById(@PathVariable("tenantId") String strTenantId) throws ThingsboardException { + public TenantInfo getTenantInfoById( + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION) + @PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException { checkParameter(TENANT_ID, strTenantId); try { TenantId tenantId = new TenantId(toUUID(strTenantId)); @@ -83,10 +95,18 @@ public class TenantController extends BaseController { } } + @ApiOperation(value = "Create Or update Tenant (saveTenant)", + notes = "Create or update the Tenant. When creating tenant, platform generates Tenant Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "Default Rule Chain and Device profile are also generated for the new tenants automatically. " + + "The newly created Tenant Id will be present in the response. " + + "Specify existing Tenant Id id to update the Tenant. " + + "Referencing non-existing Tenant Id will cause 'Not Found' error." + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenant", method = RequestMethod.POST) @ResponseBody - public Tenant saveTenant(@RequestBody Tenant tenant) throws ThingsboardException { + public Tenant saveTenant( + @ApiParam(value = "A JSON value representing the tenant.") + @RequestBody Tenant tenant) throws ThingsboardException { try { boolean newTenant = tenant.getId() == null; @@ -107,11 +127,15 @@ public class TenantController extends BaseController { } } + @ApiOperation(value = "Delete Tenant (deleteTenant)", + notes = "Deletes the tenant, it's customers, rule chains, devices and all other related entities. Referencing non-existing tenant Id will cause an error." + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteTenant(@PathVariable("tenantId") String strTenantId) throws ThingsboardException { - checkParameter("tenantId", strTenantId); + public void deleteTenant( + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION) + @PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException { + checkParameter(TENANT_ID, strTenantId); try { TenantId tenantId = new TenantId(toUUID(strTenantId)); Tenant tenant = checkTenantId(tenantId, Operation.DELETE); @@ -124,14 +148,21 @@ public class TenantController extends BaseController { } } + @ApiOperation(value = "Get Tenants (getTenants)", notes = "Returns a page of tenants registered in the platform. " + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenants", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public PageData getTenants(@RequestParam int pageSize, - @RequestParam int page, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + public PageData getTenants( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = TENANT_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = TENANT_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(tenantService.findTenants(pageLink)); @@ -140,14 +171,23 @@ public class TenantController extends BaseController { } } + @ApiOperation(value = "Get Tenants Info (getTenants)", notes = "Returns a page of tenant info objects registered in the platform. " + + TENANT_INFO_DESCRIPTION + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public PageData getTenantInfos(@RequestParam int pageSize, - @RequestParam int page, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + public PageData getTenantInfos( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = TENANT_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder + ) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(tenantService.findTenantInfos(pageLink)); diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index e201c8f815..5eddfa92f0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -44,10 +46,16 @@ import org.thingsboard.server.service.security.permission.Resource; @Slf4j public class TenantProfileController extends BaseController { + private static final String TENANT_PROFILE_INFO_DESCRIPTION = "Tenant Profile Info is a lightweight object that contains only id and name of the profile. "; + + @ApiOperation(value = "Get Tenant Profile (getTenantProfileById)", + notes = "Fetch the Tenant Profile object based on the provided Tenant Profile Id. " + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.GET) @ResponseBody - public TenantProfile getTenantProfileById(@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException { + public TenantProfile getTenantProfileById( + @ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException { checkParameter("tenantProfileId", strTenantProfileId); try { TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId)); @@ -57,10 +65,14 @@ public class TenantProfileController extends BaseController { } } + @ApiOperation(value = "Get Tenant Profile Info (getTenantProfileInfoById)", + notes = "Fetch the Tenant Profile Info object based on the provided Tenant Profile Id. " + TENANT_PROFILE_INFO_DESCRIPTION + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfileInfo/{tenantProfileId}", method = RequestMethod.GET) @ResponseBody - public EntityInfo getTenantProfileInfoById(@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException { + public EntityInfo getTenantProfileInfoById( + @ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException { checkParameter("tenantProfileId", strTenantProfileId); try { TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId)); @@ -70,6 +82,8 @@ public class TenantProfileController extends BaseController { } } + @ApiOperation(value = "Get default Tenant Profile Info (getDefaultTenantProfileInfo)", + notes = "Fetch the default Tenant Profile Info object based. " + TENANT_PROFILE_INFO_DESCRIPTION + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfileInfo/default", method = RequestMethod.GET) @ResponseBody @@ -81,10 +95,19 @@ public class TenantProfileController extends BaseController { } } + @ApiOperation(value = "Create Or update Tenant Profile (saveTenantProfile)", + notes = "Create or update the Tenant Profile. When creating tenant profile, platform generates Tenant Profile Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created Tenant Profile Id will be present in the response. " + + "Specify existing Tenant Profile Id id to update the Tenant Profile. " + + "Referencing non-existing Tenant Profile Id will cause 'Not Found' error. " + + "Update of the tenant profile configuration will cause immediate recalculation of API limits for all affected Tenants. " + + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfile", method = RequestMethod.POST) @ResponseBody - public TenantProfile saveTenantProfile(@RequestBody TenantProfile tenantProfile) throws ThingsboardException { + public TenantProfile saveTenantProfile( + @ApiParam(value = "A JSON value representing the tenant profile.") + @RequestBody TenantProfile tenantProfile) throws ThingsboardException { try { boolean newTenantProfile = tenantProfile.getId() == null; if (newTenantProfile) { @@ -105,10 +128,14 @@ public class TenantProfileController extends BaseController { } } + @ApiOperation(value = "Delete Tenant Profile (deleteTenantProfile)", + notes = "Deletes the tenant profile. Referencing non-existing tenant profile Id will cause an error. Referencing profile that is used by the tenants will cause an error. " + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteTenantProfile(@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException { + public void deleteTenantProfile( + @ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException { checkParameter("tenantProfileId", strTenantProfileId); try { TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId)); @@ -120,10 +147,14 @@ public class TenantProfileController extends BaseController { } } + @ApiOperation(value = "Make tenant profile default (setDefaultTenantProfile)", + notes = "Makes specified tenant profile to be default. Referencing non-existing tenant profile Id will cause an error. " + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfile/{tenantProfileId}/default", method = RequestMethod.POST) @ResponseBody - public TenantProfile setDefaultTenantProfile(@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException { + public TenantProfile setDefaultTenantProfile( + @ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException { checkParameter("tenantProfileId", strTenantProfileId); try { TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId)); @@ -135,14 +166,21 @@ public class TenantProfileController extends BaseController { } } + @ApiOperation(value = "Get Tenant Profiles (getTenantProfiles)", notes = "Returns a page of tenant profiles registered in the platform. " + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public PageData getTenantProfiles(@RequestParam int pageSize, - @RequestParam int page, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + public PageData getTenantProfiles( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(tenantProfileService.findTenantProfiles(getTenantId(), pageLink)); @@ -151,14 +189,22 @@ public class TenantProfileController extends BaseController { } } + @ApiOperation(value = "Get Tenant Profiles Info (getTenantProfileInfos)", notes = "Returns a page of tenant profile info objects registered in the platform. " + + TENANT_PROFILE_INFO_DESCRIPTION + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public PageData getTenantProfileInfos(@RequestParam int pageSize, - @RequestParam int page, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + public PageData getTenantProfileInfos( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(tenantProfileService.findTenantProfileInfos(getTenantId(), pageLink)); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java index f6f49bb33b..14e2ea73c1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java @@ -18,6 +18,8 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty.Access; +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.validation.NoXss; @@ -27,7 +29,9 @@ public class Customer extends ContactBased implements HasTenantId { private static final long serialVersionUID = -1599722990298929275L; @NoXss + @ApiModelProperty(position = 3, value = "Title of the customer", example = "Company A") private String title; + @ApiModelProperty(position = 5, required = true, value = "JSON object with Tenant Id") private TenantId tenantId; public Customer() { @@ -51,7 +55,7 @@ public class Customer extends ContactBased implements HasTenantId { public void setTenantId(TenantId tenantId) { this.tenantId = tenantId; } - + public String getTitle() { return title; } @@ -60,6 +64,75 @@ public class Customer extends ContactBased implements HasTenantId { this.title = title; } + @ApiModelProperty(position = 1, value = "JSON object with the customer Id. " + + "Specify this field to update the customer. " + + "Referencing non-existing customer Id will cause error. " + + "Omit this field to create new customer." ) + @Override + public CustomerId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the customer creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + + @ApiModelProperty(position = 6, required = true, value = "Country", example = "US") + @Override + public String getCountry() { + return super.getCountry(); + } + + @ApiModelProperty(position = 7, required = true, value = "State", example = "NY") + @Override + public String getState() { + return super.getState(); + } + + @ApiModelProperty(position = 8, required = true, value = "City", example = "New York") + @Override + public String getCity() { + return super.getCity(); + } + + @ApiModelProperty(position = 9, required = true, value = "Address Line 1", example = "42 Broadway Suite 12-400") + @Override + public String getAddress() { + return super.getAddress(); + } + + @ApiModelProperty(position = 10, required = true, value = "Address Line 2", example = "") + @Override + public String getAddress2() { + return super.getAddress2(); + } + + @ApiModelProperty(position = 11, required = true, value = "Zip code", example = "10004") + @Override + public String getZip() { + return super.getZip(); + } + + @ApiModelProperty(position = 12, required = true, value = "Phone number", example = "+1(415)777-7777") + @Override + public String getPhone() { + return super.getPhone(); + } + + @ApiModelProperty(position = 13, required = true, value = "Email", example = "example@company.com") + @Override + public String getEmail() { + return super.getEmail(); + } + + @ApiModelProperty(position = 14, value = "Additional parameters of the device", dataType = "com.fasterxml.jackson.databind.JsonNode") + @Override + public JsonNode getAdditionalInfo() { + return super.getAdditionalInfo(); + } + @JsonIgnore public boolean isPublic() { if (getAdditionalInfo() != null && getAdditionalInfo().has("isPublic")) { @@ -76,6 +149,7 @@ public class Customer extends ContactBased implements HasTenantId { @Override @JsonProperty(access = Access.READ_ONLY) + @ApiModelProperty(position = 4, value = "Name of the customer. Read-only, duplicated from title for backward compatibility", example = "Company A", readOnly = true) public String getName() { return title; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java index 7141382749..a35b281a46 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.Value; @@ -31,9 +32,13 @@ import java.util.UUID; @ToString(callSuper = true) public class DeviceProfileInfo extends EntityInfo { + @ApiModelProperty(position = 3, value = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ") private final String image; + @ApiModelProperty(position = 4, value = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.") private final DashboardId defaultDashboardId; + @ApiModelProperty(position = 5, value = "Type of the profile. Always 'DEFAULT' for now. Reserved for future use.") private final DeviceProfileType type; + @ApiModelProperty(position = 6, value = "Type of the transport used to connect the device. Default transport supports HTTP, CoAP and MQTT.") private final DeviceTransportType transportType; @JsonCreator diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityInfo.java index 3162d66dbb..b551583503 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityInfo.java @@ -17,6 +17,8 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -24,10 +26,13 @@ import org.thingsboard.server.common.data.id.HasId; import java.util.UUID; +@ApiModel @Data public class EntityInfo implements HasId, HasName { + @ApiModelProperty(position = 1, value = "JSON object with the entity Id. ") private final EntityId id; + @ApiModelProperty(position = 2, value = "Entity Name") private final String name; @JsonCreator diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java index b6adf6cf65..f797591ccf 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java @@ -17,20 +17,28 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.validation.NoXss; +@ApiModel @EqualsAndHashCode(callSuper = true) public class Tenant extends ContactBased implements HasTenantId { private static final long serialVersionUID = 8057243243859922101L; @NoXss + @ApiModelProperty(position = 3, value = "Title of the tenant", example = "Company A") private String title; @NoXss + @ApiModelProperty(position = 5, value = "Geo region of the tenant", example = "North America") private String region; + + @ApiModelProperty(position = 6, required = true, value = "JSON object with Tenant Profile Id") private TenantProfileId tenantProfileId; public Tenant() { @@ -63,6 +71,7 @@ public class Tenant extends ContactBased implements HasTenantId { } @Override + @ApiModelProperty(position = 4, value = "Name of the tenant. Read-only, duplicated from title for backward compatibility", example = "Company A", readOnly = true) @JsonProperty(access = JsonProperty.Access.READ_ONLY) public String getName() { return title; @@ -89,6 +98,75 @@ public class Tenant extends ContactBased implements HasTenantId { return getTitle(); } + @ApiModelProperty(position = 1, value = "JSON object with the tenant Id. " + + "Specify this field to update the tenant. " + + "Referencing non-existing tenant Id will cause error. " + + "Omit this field to create new tenant." ) + @Override + public TenantId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the tenant creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + + @ApiModelProperty(position = 7, required = true, value = "Country", example = "US") + @Override + public String getCountry() { + return super.getCountry(); + } + + @ApiModelProperty(position = 8, required = true, value = "State", example = "NY") + @Override + public String getState() { + return super.getState(); + } + + @ApiModelProperty(position = 9, required = true, value = "City", example = "New York") + @Override + public String getCity() { + return super.getCity(); + } + + @ApiModelProperty(position = 10, required = true, value = "Address Line 1", example = "42 Broadway Suite 12-400") + @Override + public String getAddress() { + return super.getAddress(); + } + + @ApiModelProperty(position = 11, required = true, value = "Address Line 2", example = "") + @Override + public String getAddress2() { + return super.getAddress2(); + } + + @ApiModelProperty(position = 12, required = true, value = "Zip code", example = "10004") + @Override + public String getZip() { + return super.getZip(); + } + + @ApiModelProperty(position = 13, required = true, value = "Phone number", example = "+1(415)777-7777") + @Override + public String getPhone() { + return super.getPhone(); + } + + @ApiModelProperty(position = 14, required = true, value = "Email", example = "example@company.com") + @Override + public String getEmail() { + return super.getEmail(); + } + + @ApiModelProperty(position = 15, value = "Additional parameters of the device", dataType = "com.fasterxml.jackson.databind.JsonNode") + @Override + public JsonNode getAdditionalInfo() { + return super.getAdditionalInfo(); + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TenantInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/TenantInfo.java index acc83eca6f..4a98262f14 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TenantInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TenantInfo.java @@ -15,12 +15,15 @@ */ package org.thingsboard.server.common.data; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.TenantId; +@ApiModel @Data public class TenantInfo extends Tenant { - + @ApiModelProperty(position = 15, value = "Tenant Profile name", example = "Default") private String tenantProfileName; public TenantInfo() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java index 05d22af09f..2d1a575f1c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java @@ -17,6 +17,8 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -31,18 +33,27 @@ import java.util.Optional; import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.mapper; +@ApiModel @Data @EqualsAndHashCode(callSuper = true) @Slf4j public class TenantProfile extends SearchTextBased implements HasName { @NoXss + @ApiModelProperty(position = 3, value = "Name of the tenant profile", example = "High Priority Tenants") private String name; @NoXss + @ApiModelProperty(position = 4, value = "Description of the tenant profile", example = "Any text") private String description; + @ApiModelProperty(position = 5, value = "Default Tenant profile to be used.", example = "true") private boolean isDefault; + @ApiModelProperty(position = 6, value = "If enabled, will push all messages related to this tenant and processed by core platform services into separate queue. " + + "Useful for complex microservices deployments, to isolate processing of the data for specific tenants", example = "true") private boolean isolatedTbCore; + @ApiModelProperty(position = 7, value = "If enabled, will push all messages related to this tenant and processed by the rule engine into separate queue. " + + "Useful for complex microservices deployments, to isolate processing of the data for specific tenants", example = "true") private boolean isolatedTbRuleEngine; + @ApiModelProperty(position = 8, value = "Complex JSON object that contains profile settings: max devices, max assets, rate limits, etc.") private transient TenantProfileData profileData; @JsonIgnore private byte[] profileDataBytes; @@ -65,6 +76,21 @@ public class TenantProfile extends SearchTextBased implements H this.setProfileData(tenantProfile.getProfileData()); } + @ApiModelProperty(position = 1, value = "JSON object with the tenant profile Id. " + + "Specify this field to update the tenant profile. " + + "Referencing non-existing tenant profile Id will cause error. " + + "Omit this field to create new tenant profile." ) + @Override + public TenantProfileId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the tenant profile creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + @Override public String getSearchText() { return getName(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index ce10f95055..7d4459c6d0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.tenant.profile; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java index d88b92babc..6316305127 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.annotations.ApiModel; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.TenantProfileType; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java index aaa22532bc..3138650504 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java @@ -15,11 +15,15 @@ */ package org.thingsboard.server.common.data.tenant.profile; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; +@ApiModel @Data public class TenantProfileData { + @ApiModelProperty(position = 1, value = "Complex JSON object that contains profile settings: max devices, max assets, rate limits, etc.") private TenantProfileConfiguration configuration; } From cbadb87296940c9cb7a863c9047db7b88866ab26 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Tue, 19 Oct 2021 18:23:55 +0300 Subject: [PATCH 089/303] device profile data documentation --- .../server/controller/BaseController.java | 39 +++++++++++++++++++ .../controller/DeviceProfileController.java | 14 ++++++- .../server/controller/EventController.java | 2 - .../server/common/data/alarm/Alarm.java | 4 +- .../data/device/data/DeviceConfiguration.java | 4 +- .../common/data/device/data/DeviceData.java | 3 ++ .../data/DeviceTransportConfiguration.java | 5 ++- .../data/device/profile/AlarmCondition.java | 5 +++ .../device/profile/AlarmConditionFilter.java | 7 ++++ .../profile/AlarmConditionFilterKey.java | 5 +++ .../device/profile/AlarmConditionSpec.java | 6 ++- .../common/data/device/profile/AlarmRule.java | 7 ++++ .../data/device/profile/AlarmSchedule.java | 4 ++ .../device/profile/DeviceProfileAlarm.java | 12 ++++++ .../profile/DeviceProfileConfiguration.java | 6 ++- .../device/profile/DeviceProfileData.java | 7 ++++ .../DeviceProfileProvisionConfiguration.java | 7 +++- .../common/data/query/KeyFilterPredicate.java | 6 ++- 18 files changed, 126 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 0a62409891..3cb8e211cd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -244,11 +244,50 @@ public abstract class BaseController { protected static final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; protected static final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_CREATE_RULES_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{ \"createRules\": { \"MAJOR\": { \"schedule\": null, \"condition\": { \"spec\": { \"type\": \"SIMPLE\" }, " + + "\"condition\": [{ \"key\": { \"key\": \"temp\", \"type\": \"TIME_SERIES\" }, \"value\": null, \"predicate\": { \"type\": \"NUMERIC\", \"value\": { \"userValue\": null, \"defaultValue\": 30.0, \"dynamicValue\": null }, " + + "\"operation\": \"GREATER\" }, \"valueType\": \"NUMERIC\" }] }, \"dashboardId\": null, \"alarmDetails\": null }, \"CRITICAL\": { \"schedule\": null, \"condition\": { \"spec\": { \"type\": \"SIMPLE\" }, \"condition\": " + + "[{ \"key\": { \"key\": \"temp\", \"type\": \"TIME_SERIES\" }, \"value\": null, \"predicate\": { \"type\": \"NUMERIC\", \"value\": { \"userValue\": null, \"defaultValue\": 50.0, \"dynamicValue\": null }, \"operation\": \"GREATER\" }, " + + "\"valueType\": \"NUMERIC\" }] }, \"dashboardId\": null, \"alarmDetails\": null } } }" + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{ \"schedule\": { \"type\": \"SPECIFIC_TIME\", \"endsOn\": 64800000, \"startsOn\": 43200000, \"timezone\": \"Europe/Kiev\", \"daysOfWeek\": [1, 3, 7] } }" + + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{ \"schedule\": { \"type\": \"CUSTOM\", \"items\": [{ \"endsOn\": 64800000, \"enabled\": true, \"startsOn\": 43200000, \"dayOfWeek\": 1 }, " + + "{ \"endsOn\": 0, \"enabled\": false, \"startsOn\": 0, \"dayOfWeek\": 2 }, { \"endsOn\": 57600000, \"enabled\": true, \"startsOn\": 36000000, \"dayOfWeek\": 3 }, " + + "{ \"endsOn\": 0, \"enabled\": false, \"startsOn\": 0, \"dayOfWeek\": 4 }, { \"endsOn\": 68400000, \"enabled\": true, \"startsOn\": 32400000, \"dayOfWeek\": 5 }, " + + "{ \"endsOn\": 0, \"enabled\": false, \"startsOn\": 0, \"dayOfWeek\": 6 }, { \"endsOn\": 0, \"enabled\": false, \"startsOn\": 0, \"dayOfWeek\": 7 }], \"timezone\": \"Europe/Kiev\" } }" + + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\"schedule\": null}" + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{ \"spec\": { \"type\": \"DURATION\", \"unit\": \"MINUTES\", \"predicate\": { \"userValue\": null, \"defaultValue\": 30, \"dynamicValue\": null } } }" + + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{ \"spec\": { \"type\": \"REPEATING\", \"predicate\": { \"userValue\": null, \"defaultValue\": 3, \"dynamicValue\": " + + "{ \"inherit\": false, \"sourceType\": \"CURRENT_DEVICE\", \"sourceAttribute\": \"repeatingLimit\" } } } }" + + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_PROFILE_CONDITIONS_TIME_SERIES_NUMERIC_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{ \"condition\": [{ \"key\": { \"key\": \"temp\", \"type\": \"TIME_SERIES\" }, " + + "\"value\": null, \"predicate\": { \"type\": \"NUMERIC\", \"value\": { \"userValue\": null, \"defaultValue\": 30.0, \"dynamicValue\": null }, \"operation\": \"GREATER\" }, " + + "\"valueType\": \"NUMERIC\" }] }" + + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_PROFILE_CONDITIONS_CONSTANT_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{ \"condition\": [{ \"key\": { \"key\": \"constantKey\", \"type\": \"CONSTANT\" }, \"value\": true, \"predicate\": { \"type\": \"BOOLEAN\", \"value\": " + + "{ \"userValue\": null, \"defaultValue\": false, \"dynamicValue\": { \"inherit\": false, \"sourceType\": \"CURRENT_TENANT\", \"sourceAttribute\": \"alarmEnabled\" } }, " + + "\"operation\": \"EQUAL\" }, \"valueType\": \"BOOLEAN\" }] }" + + MARKDOWN_CODE_BLOCK_END; + protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; protected static final String ADMINISTRATOR_AUTHORITY_ONLY = "Available for users with 'Tenant Administrator' authority only."; + protected static final String NEW_LINE = "\n\n"; + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; protected static final String HOME_DASHBOARD = "homeDashboardId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index cae479814d..05e62becdb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -174,7 +174,19 @@ public class DeviceProfileController extends BaseController { "The newly created device profile id will be present in the response. " + "Specify existing device profile id to update the device profile. " + "Referencing non-existing device profile Id will cause 'Not Found' error. " + - "\n\nDevice profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + TENANT_AUTHORITY_PARAGRAPH, + "\n\nDevice profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + TENANT_AUTHORITY_PARAGRAPH + + NEW_LINE + "See the object example below for createRules field:" + NEW_LINE + DEVICE_PROFILE_ALARM_CREATE_RULES_EXAMPLE + + NEW_LINE + "See alarm schedule objects examples below. Note," + NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE + NEW_LINE + " means alarm rule is active all the time. " + + "'daysOfWeek' field represents Monday as 1, Tuesday as 2 and so on. 'startsOn' and 'endsOn' represent hours in millis. " + + "'enabled' flag represents if custom rule is active for specific day of the week:" + NEW_LINE + + DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE + NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE + NEW_LINE + + "Alarm condition type ('spec') can be either simple, duration, or repeating. For example, 5 times in a row or during 5 minutes. See examples below. " + NEW_LINE + + DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE + NEW_LINE + DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE + NEW_LINE + + "Note, 'userValue' field is not used, 'dynamicValue' is used for condition appliance from the 'sourceAttribute' or else 'defaultValue' is used. " + + "'sourceType' of the 'sourceAttribute' can be CURRENT_DEVICE/CURRENT_CUSTOMER/CURRENT_TENANT or inherited from the owner if set to true (for device and customer)." + + NEW_LINE + "Condition array examples for alarm rule activation:" + NEW_LINE + DEVICE_PROFILE_CONDITIONS_TIME_SERIES_NUMERIC_EXAMPLE + NEW_LINE + + DEVICE_PROFILE_CONDITIONS_CONSTANT_EXAMPLE + NEW_LINE + + "Note, see description of predicate fields above for 'spec' object. Navigate to Docs or Alarm Rules on ThingsBoard UI for more details and examples of fields possible values. ", produces = "application/json", consumes = "application/json") @PreAuthorize("hasAuthority('TENANT_ADMIN')") diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 097e18d406..98031fefd5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -45,8 +45,6 @@ import org.thingsboard.server.service.security.permission.Operation; @RequestMapping("/api") public class EventController extends BaseController { - private static final String NEW_LINE = "\n\n"; - @Autowired private EventService eventService; 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 cb73aeb5e0..b59d62bda6 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 @@ -69,8 +69,8 @@ public class Alarm extends BaseData implements HasName, HasTenantId, Ha @ApiModelProperty(position = 15, value = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true") private boolean propagate; @ApiModelProperty(position = 16, value = "JSON array of relation types that should be used for propagation. " + - "By default, 'propagateRelationTypes' array is empty which means that the alarm will propagate based on any relation type to parent entities. " + - "This parameter should be used only in case when 'propagate' parameter is set to true, otherwise, 'propagateRelationTypes' array will ignoned.") + "By default, 'propagateRelationTypes' array is empty which means that the alarm will be propagated based on any relation type to parent entities. " + + "This parameter should be used only in case when 'propagate' parameter is set to true, otherwise, 'propagateRelationTypes' array will be ignored.") private List propagateRelationTypes; public Alarm() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java index 16f751a136..46d7a3d615 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java @@ -15,11 +15,11 @@ */ package org.thingsboard.server.common.data.device.data; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.DeviceProfileType; @ApiModel @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.DeviceProfileType; @JsonSubTypes.Type(value = DefaultDeviceConfiguration.class, name = "DEFAULT")}) public interface DeviceConfiguration { - @JsonIgnore + @ApiModelProperty(position = 1, value = "Device profile type", allowableValues = "DEFAULT") DeviceProfileType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceData.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceData.java index 06e52d47a0..26266b2b18 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceData.java @@ -16,13 +16,16 @@ package org.thingsboard.server.common.data.device.data; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; @ApiModel @Data public class DeviceData { + @ApiModelProperty(position = 1, value = "Device configuration for device profile type. DEFAULT is only supported value for now") private DeviceConfiguration configuration; + @ApiModelProperty(position = 2, value = "Device transport configuration used to connect the device") private DeviceTransportConfiguration transportConfiguration; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceTransportConfiguration.java index e39ed8ac15..bfa7fc672c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceTransportConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceTransportConfiguration.java @@ -15,11 +15,11 @@ */ package org.thingsboard.server.common.data.device.data; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.DeviceTransportType; import java.io.Serializable; @@ -37,7 +37,8 @@ import java.io.Serializable; @JsonSubTypes.Type(value = Lwm2mDeviceTransportConfiguration.class, name = "LWM2M"), @JsonSubTypes.Type(value = SnmpDeviceTransportConfiguration.class, name = "SNMP")}) public interface DeviceTransportConfiguration extends Serializable { - @JsonIgnore + + @ApiModelProperty(position = 1, value = "Device transport type", example = "MQTT") DeviceTransportType getType(); default void validate() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmCondition.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmCondition.java index 90de622fb0..1898d201ee 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmCondition.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmCondition.java @@ -16,18 +16,23 @@ package org.thingsboard.server.common.data.device.profile; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; import javax.validation.Valid; import java.util.List; +@ApiModel @Data @JsonIgnoreProperties(ignoreUnknown = true) public class AlarmCondition implements Serializable { @Valid + @ApiModelProperty(position = 1, value = "JSON array of alarm condition filters") private List condition; + @ApiModelProperty(position = 2, value = "JSON object representing alarm condition type") private AlarmConditionSpec spec; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionFilter.java index 96fbd3465f..5a45fa6d68 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionFilter.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.device.profile; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.query.EntityKeyValueType; import org.thingsboard.server.common.data.query.KeyFilterPredicate; @@ -24,15 +26,20 @@ import javax.validation.Valid; import java.io.Serializable; +@ApiModel @Data public class AlarmConditionFilter implements Serializable { @Valid + @ApiModelProperty(position = 1, value = "JSON object for specifying alarm condition by specific key") private AlarmConditionFilterKey key; + @ApiModelProperty(position = 2, value = "String representation of the type of the value", example = "NUMERIC") private EntityKeyValueType valueType; @NoXss + @ApiModelProperty(position = 3, value = "Value used in Constant comparison. For other types, such as TIME_SERIES or ATTRIBUTE, the predicate condition is used") private Object value; @Valid + @ApiModelProperty(position = 4, value = "JSON object representing filter condition") private KeyFilterPredicate predicate; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionFilterKey.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionFilterKey.java index 258e50a6a0..737db08c0b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionFilterKey.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionFilterKey.java @@ -15,16 +15,21 @@ */ package org.thingsboard.server.common.data.device.profile; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.validation.NoXss; import java.io.Serializable; +@ApiModel @Data public class AlarmConditionFilterKey implements Serializable { + @ApiModelProperty(position = 1, value = "The key type", example = "TIME_SERIES") private final AlarmConditionKeyType type; @NoXss + @ApiModelProperty(position = 2, value = "String value representing the key", example = "temp") private final String key; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java index 1a34894997..d1346d9778 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java @@ -15,13 +15,15 @@ */ package org.thingsboard.server.common.data.device.profile; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; +@ApiModel @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -33,7 +35,7 @@ import java.io.Serializable; @JsonSubTypes.Type(value = RepeatingAlarmConditionSpec.class, name = "REPEATING")}) public interface AlarmConditionSpec extends Serializable { - @JsonIgnore + @ApiModelProperty(position = 1, value = "String value representing alarm condition type. See method implementation notes for more examples") AlarmConditionSpecType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java index f578cd15c3..8304a1fc6a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.device.profile; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.validation.NoXss; @@ -23,15 +25,20 @@ import javax.validation.Valid; import java.io.Serializable; +@ApiModel @Data public class AlarmRule implements Serializable { @Valid + @ApiModelProperty(position = 1, value = "JSON object representing the alarm rule condition") private AlarmCondition condition; + @ApiModelProperty(position = 2, value = "JSON object representing time interval during which the rule is active") private AlarmSchedule schedule; // Advanced @NoXss + @ApiModelProperty(position = 3, value = "String value representing the additional details for an alarm rule") private String alarmDetails; + @ApiModelProperty(position = 4, value = "JSON object with the dashboard Id representing the reference to alarm details dashboard used by mobile application") private DashboardId dashboardId; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java index 1d5eceb1aa..bf898603a3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java @@ -18,9 +18,12 @@ package org.thingsboard.server.common.data.device.profile; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; +@ApiModel @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -32,6 +35,7 @@ import java.io.Serializable; @JsonSubTypes.Type(value = CustomTimeSchedule.class, name = "CUSTOM")}) public interface AlarmSchedule extends Serializable { + @ApiModelProperty(position = 1, value = "Alarm schedule type. See method implementation notes for more examples", example = "ANY_TIME") AlarmScheduleType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java index 7a99ccb41e..abbb7858ff 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.device.profile; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.validation.NoXss; @@ -24,19 +26,29 @@ import javax.validation.Valid; import java.util.List; import java.util.TreeMap; +@ApiModel @Data public class DeviceProfileAlarm implements Serializable { + @ApiModelProperty(position = 1, value = "String value representing the alarm rule id", example = "highTemperatureAlarmID") private String id; @NoXss + @ApiModelProperty(position = 2, value = "String value representing type of the Alarm", example = "High Temperature Alarm") private String alarmType; @Valid + @ApiModelProperty(position = 3, value = "Complex JSON object representing create alarm rules. The unique create alarm rule can be created for each alarm severity type. " + + "There can be 5 create alarm rules configured per a single alarm type. See method implementation notes and AlarmRule model for more details") private TreeMap createRules; @Valid + @ApiModelProperty(position = 4, value = "JSON object representing clear alarm rule") private AlarmRule clearRule; // Hidden in advanced settings + @ApiModelProperty(position = 5, value = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true") private boolean propagate; + @ApiModelProperty(position = 6, value = "JSON array of relation types that should be used for propagation. " + + "By default, 'propagateRelationTypes' array is empty which means that the alarm will be propagated based on any relation type to parent entities. " + + "This parameter should be used only in case when 'propagate' parameter is set to true, otherwise, 'propagateRelationTypes' array will be ignored.") private List propagateRelationTypes; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java index ce019212eb..f1792225fb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java @@ -15,14 +15,16 @@ */ package org.thingsboard.server.common.data.device.profile; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.DeviceProfileType; import java.io.Serializable; +@ApiModel @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -32,7 +34,7 @@ import java.io.Serializable; @JsonSubTypes.Type(value = DefaultDeviceProfileConfiguration.class, name = "DEFAULT")}) public interface DeviceProfileConfiguration extends Serializable { - @JsonIgnore + @ApiModelProperty(position = 1, value = "Device profile type", allowableValues = "DEFAULT") DeviceProfileType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java index f77e6388a5..adeb77d315 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java @@ -15,20 +15,27 @@ */ package org.thingsboard.server.common.data.device.profile; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; import javax.validation.Valid; import java.util.List; +@ApiModel @Data public class DeviceProfileData implements Serializable { + @ApiModelProperty(position = 1, value = "JSON object of device profile configuration for device profile type") private DeviceProfileConfiguration configuration; @Valid + @ApiModelProperty(position = 2, value = "JSON object of device profile transport configuration") private DeviceProfileTransportConfiguration transportConfiguration; + @ApiModelProperty(position = 3, value = "JSON object of provisioning strategy type per device profile") private DeviceProfileProvisionConfiguration provisionConfiguration; @Valid + @ApiModelProperty(position = 4, value = "JSON array of alarm rules configuration per device profile") private List alarms; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileProvisionConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileProvisionConfiguration.java index 2b0f1b8da1..869a6ce0f8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileProvisionConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileProvisionConfiguration.java @@ -19,11 +19,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import java.io.Serializable; - +@ApiModel @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -35,9 +37,10 @@ import java.io.Serializable; @JsonSubTypes.Type(value = CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration.class, name = "CHECK_PRE_PROVISIONED_DEVICES")}) public interface DeviceProfileProvisionConfiguration extends Serializable { + @ApiModelProperty(position = 1, value = "String value representing the secret key used to verify provisioning of the device defined in the device profile", example = "bjrj9172va82hvwqtp5b") String getProvisionDeviceSecret(); - @JsonIgnore + @ApiModelProperty(position = 2, value = "Device provisioning strategy for device profile", example = "ALLOW_CREATE_NEW_DEVICES") DeviceProfileProvisionType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilterPredicate.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilterPredicate.java index 79f2f0e132..7d12c4d460 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilterPredicate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilterPredicate.java @@ -15,12 +15,14 @@ */ package org.thingsboard.server.common.data.query; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; +@ApiModel @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, @@ -32,7 +34,7 @@ import java.io.Serializable; @JsonSubTypes.Type(value = ComplexFilterPredicate.class, name = "COMPLEX")}) public interface KeyFilterPredicate extends Serializable { - @JsonIgnore + @ApiModelProperty(position = 1, value = "String value representing filter predicate type. See method implementation notes for more examples", example = "BOOLEAN") FilterPredicateType getType(); } From 991ef278d8947f68d4d293cb94d2f4290dd87585 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 19 Oct 2021 18:58:07 +0300 Subject: [PATCH 090/303] Tenant Profile Description improved --- .../controller/EntityQueryController.java | 2 +- .../server/controller/TenantController.java | 3 +- .../controller/TenantProfileController.java | 53 ++++++++++++++++++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 33e819ff00..2e815bdc7e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -415,7 +415,7 @@ public class EntityQueryController extends BaseController { " ]\n" + "}" + MARKDOWN_CODE_BLOCK_END + - "\n\n YOu may also want to replace hardcoded values (for example, temperature > 20) with the more dynamic " + + "\n\n You may also want to replace hardcoded values (for example, temperature > 20) with the more dynamic " + "expression (for example, temperature > 'value of the tenant attribute with key 'temperatureThreshold'). " + "It is possible to use 'dynamicValue' to define attribute of the tenant, customer or user that is performing the API call. " + "See example below: \n\n" + diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index c3e2492632..e083c12440 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -100,7 +100,8 @@ public class TenantController extends BaseController { "Default Rule Chain and Device profile are also generated for the new tenants automatically. " + "The newly created Tenant Id will be present in the response. " + "Specify existing Tenant Id id to update the Tenant. " + - "Referencing non-existing Tenant Id will cause 'Not Found' error." + SYSTEM_AUTHORITY_PARAGRAPH) + "Referencing non-existing Tenant Id will cause 'Not Found' error." + + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenant", method = RequestMethod.POST) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index 5eddfa92f0..6223f750a5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -100,7 +100,58 @@ public class TenantProfileController extends BaseController { "The newly created Tenant Profile Id will be present in the response. " + "Specify existing Tenant Profile Id id to update the Tenant Profile. " + "Referencing non-existing Tenant Profile Id will cause 'Not Found' error. " + - "Update of the tenant profile configuration will cause immediate recalculation of API limits for all affected Tenants. " + + "\n\nUpdate of the tenant profile configuration will cause immediate recalculation of API limits for all affected Tenants. " + + "\n\nThe **'profileData'** object is the part of Tenant Profile that defines API limits and Rate limits. " + + "\n\nYou have an ability to define maximum number of devices ('maxDevice'), assets ('maxAssets') and other entities. " + + "You may also define maximum number of messages to be processed per month ('maxTransportMessages', 'maxREExecutions', etc). " + + "The '*RateLimit' defines the rate limits using simple syntax. For example, '1000:1,20000:60' means up to 1000 events per second but no more than 20000 event per minute. " + + "Let's review the example of tenant profile data below: " + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"id\": {\n" + + " \"entityType\": \"TENANT_PROFILE\",\n" + + " \"id\": \"0f2978a0-0d46-11eb-ab90-09ceaa526dd8\"\n" + + " },\n" + + " \"createdTime\": 1602588011818,\n" + + " \"name\": \"Default\",\n" + + " \"description\": \"Default tenant profile\",\n" + + " \"isolatedTbCore\": false,\n" + + " \"isolatedTbRuleEngine\": false,\n" + + " \"profileData\": {\n" + + " \"configuration\": {\n" + + " \"type\": \"DEFAULT\",\n" + + " \"maxDevices\": 0,\n" + + " \"maxAssets\": 0,\n" + + " \"maxCustomers\": 0,\n" + + " \"maxUsers\": 0,\n" + + " \"maxDashboards\": 0,\n" + + " \"maxRuleChains\": 0,\n" + + " \"maxResourcesInBytes\": 0,\n" + + " \"maxOtaPackagesInBytes\": 0,\n" + + " \"transportTenantMsgRateLimit\": \"1000:1,20000:60\",\n" + + " \"transportTenantTelemetryMsgRateLimit\": \"1000:1,20000:60\",\n" + + " \"transportTenantTelemetryDataPointsRateLimit\": \"1000:1,20000:60\",\n" + + " \"transportDeviceMsgRateLimit\": \"20:1,600:60\",\n" + + " \"transportDeviceTelemetryMsgRateLimit\": \"20:1,600:60\",\n" + + " \"transportDeviceTelemetryDataPointsRateLimit\": \"20:1,600:60\",\n" + + " \"maxTransportMessages\": 10000000,\n" + + " \"maxTransportDataPoints\": 10000000,\n" + + " \"maxREExecutions\": 4000000,\n" + + " \"maxJSExecutions\": 5000000,\n" + + " \"maxDPStorageDays\": 0,\n" + + " \"maxRuleNodeExecutionsPerMessage\": 50,\n" + + " \"maxEmails\": 0,\n" + + " \"maxSms\": 0,\n" + + " \"maxCreatedAlarms\": 1000,\n" + + " \"defaultStorageTtlDays\": 0,\n" + + " \"alarmsTtlDays\": 0,\n" + + " \"rpcTtlDays\": 0,\n" + + " \"warnThreshold\": 0\n" + + " }\n" + + " },\n" + + " \"default\": true\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenantProfile", method = RequestMethod.POST) From 6521caf0040d1863b5483f427d6d74dcd9ea211c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 19 Oct 2021 19:03:53 +0300 Subject: [PATCH 091/303] Lwm2m awake only if state - Registration --- .../transport/lwm2m/server/LwM2mVersionedModelProvider.java | 4 ++-- .../server/downlink/DefaultLwM2mDownlinkMsgHandler.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java index ad31c674c3..0667c46da8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java @@ -95,7 +95,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { if (objectModel != null) return objectModel.resources.get(resourceId); else - log.trace("TbResources (Object model) with id [{}/0/{}] not found on the server.", objectId, resourceId); + log.trace("Tenant hasn't such the TbResources: Object model with id [{}/0/{}].", objectId, resourceId); return null; } catch (Exception e) { log.error("", e); @@ -138,7 +138,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { if (objectModel != null) { models.get(tenantId).put(key, objectModel); } else { - log.error("Object model with id [{}] version [{}] not found on the server.", objectId, version); + log.error("Tenant hasn't such the resource: Object model with id [{}] version [{}].", objectId, version); } } finally { modelsLock.unlock(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index ccfcd57163..681ae6e8f0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -187,7 +187,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); + callback.onValidationError(toString(request), "Tenant hasn't such the TbResources: " + request.getVersionedId() + "!"); } } @@ -248,7 +248,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im callback.onError(toString(request), e); } } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); + callback.onValidationError(toString(request), "Tenant hasn't such the TbResources: " + request.getVersionedId() + "!"); } } @@ -281,7 +281,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); + callback.onValidationError(toString(request), "Tenant hasn't such the TbResources: " + request.getVersionedId() + " !"); } } else if (resultIds.isObjectInstance()) { /* From 9bdc56f68c9d5ef6d1fcd866a9cd6e695217bfd6 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 19 Oct 2021 22:22:06 +0300 Subject: [PATCH 092/303] Add widgets help resources. Introduce datasources optional flag for widget type parameters. --- .../system/widget_bundles/alarm_widgets.json | 4 +- .../json/system/widget_bundles/cards.json | 18 +-- ui-ngx/src/app/core/api/alias-controller.ts | 3 + .../src/app/core/api/widget-subscription.ts | 2 +- .../dashboard-page.component.ts | 1 + .../widget/lib/flot-widget.models.ts | 20 ++-- .../widget/lib/markdown-widget.component.ts | 2 + .../widget/widget-component.service.ts | 3 + .../widget/widget-config.component.ts | 2 +- ui-ngx/src/app/shared/models/widget.models.ts | 1 + .../widget/config/datakey_generation_fn.md | 3 + .../widget/config/datakey_postprocess_fn.md | 3 + .../en_US/widget/lib/alarm/cell_content_fn.md | 52 ++++++++ .../en_US/widget/lib/alarm/cell_style_fn.md | 62 ++++++++++ .../en_US/widget/lib/alarm/row_style_fn.md | 59 ++++++++++ .../entities_hierarchy/node_disabled_fn.md | 40 +++++++ .../node_has_children_fn.md | 47 ++++++++ .../lib/entities_hierarchy/node_icon_fn.md | 53 +++++++++ .../lib/entities_hierarchy/node_opened_fn.md | 35 ++++++ .../node_relation_query_fn.md | 49 ++++++++ .../lib/entities_hierarchy/node_text_fn.md | 41 +++++++ .../lib/entities_hierarchy/nodes_sort_fn.md | 44 +++++++ .../widget/lib/entity/cell_content_fn.md | 61 ++++++++++ .../en_US/widget/lib/entity/cell_style_fn.md | 52 ++++++++ .../en_US/widget/lib/entity/row_style_fn.md | 50 ++++++++ .../widget/lib/flot/point_shape_format_fn.md | 111 ++++++++++++++++++ .../widget/lib/flot/ticks_formatter_fn.md | 93 +++++++++++++++ .../lib/{ => flot}/tooltip_value_format_fn.md | 3 + .../widget/lib/timeseries/cell_content_fn.md | 53 +++++++++ .../widget/lib/timeseries/cell_style_fn.md | 52 ++++++++ .../widget/lib/timeseries/row_style_fn.md | 49 ++++++++ 31 files changed, 1047 insertions(+), 21 deletions(-) create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/alarm/cell_content_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/alarm/cell_style_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/alarm/row_style_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_disabled_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_has_children_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_icon_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_opened_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_relation_query_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_text_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/nodes_sort_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_content_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_style_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/entity/row_style_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/flot/point_shape_format_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/flot/ticks_formatter_fn.md rename ui-ngx/src/assets/help/en_US/widget/lib/{ => flot}/tooltip_value_format_fn.md (98%) create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/timeseries/cell_content_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/timeseries/cell_style_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/timeseries/row_style_fn.md diff --git a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json index 47674c7727..a5b5146004 100644 --- a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json @@ -19,8 +19,8 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.alarmsTableWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"AlarmTableSettings\",\n \"properties\": {\n \"alarmsTitle\": {\n \"title\": \"Alarms table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSelection\": {\n \"title\": \"Enable alarms selection\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSearch\": {\n \"title\": \"Enable alarms search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableFilter\": {\n \"title\": \"Enable alarm filter\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayDetails\": {\n \"title\": \"Display alarm details\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowAcknowledgment\": {\n \"title\": \"Allow alarms acknowledgment\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowClear\": {\n \"title\": \"Allow alarms clear\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"-createdTime\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(alarm, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"alarmsTitle\",\n \"enableSelection\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableFilter\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayDetails\",\n \"allowAcknowledgment\",\n \"allowClear\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, alarm, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, alarm, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"AlarmTableSettings\",\n \"properties\": {\n \"alarmsTitle\": {\n \"title\": \"Alarms table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSelection\": {\n \"title\": \"Enable alarms selection\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSearch\": {\n \"title\": \"Enable alarms search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableFilter\": {\n \"title\": \"Enable alarm filter\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayDetails\": {\n \"title\": \"Display alarm details\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowAcknowledgment\": {\n \"title\": \"Allow alarms acknowledgment\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowClear\": {\n \"title\": \"Allow alarms clear\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"-createdTime\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(alarm, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"alarmsTitle\",\n \"enableSelection\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableFilter\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayDetails\",\n \"allowAcknowledgment\",\n \"allowClear\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/alarm/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, alarm, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, alarm, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/alarm/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/alarm/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false}" } } diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index d0e91bedd7..384fadd463 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -55,8 +55,8 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n ignoreDataUpdateOnIntervalTick: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"enableSearch\": {\n \"title\": \"Enable search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showMilliseconds\": {\n \"title\": \"Display timestamp milliseconds\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n }, \n \"useEntityLabel\": {\n \"title\": \"Use entity label in tab name\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"hideEmptyLines\": {\n \"title\": \"Hide empty lines\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"disableStickyHeader\": {\n \"title\": \"Disable sticky header\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"enableSearch\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"showTimestamp\",\n \"showMilliseconds\",\n \"displayPagination\",\n \"useEntityLabel\",\n \"defaultPageSize\",\n \"identifyDeviceSelector\",\n \"hideEmptyLines\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"enableSearch\": {\n \"title\": \"Enable search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showMilliseconds\": {\n \"title\": \"Display timestamp milliseconds\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n }, \n \"useEntityLabel\": {\n \"title\": \"Use entity label in tab name\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"hideEmptyLines\": {\n \"title\": \"Hide empty lines\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"disableStickyHeader\": {\n \"title\": \"Disable sticky header\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"enableSearch\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"showTimestamp\",\n \"showMilliseconds\",\n \"displayPagination\",\n \"useEntityLabel\",\n \"defaultPageSize\",\n \"identifyDeviceSelector\",\n \"hideEmptyLines\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n }\n ]\n}", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\"}" } }, @@ -127,8 +127,8 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true},\"title\":\"Entities table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}]}" } }, @@ -145,7 +145,7 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesHierarchyWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'nodeSelected': {\n name: 'widget-action.node-selected',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesHierarchySettings\",\n \"properties\": {\n \"nodeRelationQueryFunction\": {\n \"title\": \"Node relations query function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeHasChildrenFunction\": {\n \"title\": \"Node has children function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeOpenedFunction\": {\n \"title\": \"Default node opened function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeDisabledFunction\": {\n \"title\": \"Node disabled function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeIconFunction\": {\n \"title\": \"Node icon function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeTextFunction\": {\n \"title\": \"Node text function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodesSortFunction\": {\n \"title\": \"Nodes sort function: f(nodeCtx1, nodeCtx2)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"nodeRelationQueryFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeHasChildrenFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeOpenedFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeDisabledFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeIconFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeTextFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodesSortFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesHierarchySettings\",\n \"properties\": {\n \"nodeRelationQueryFunction\": {\n \"title\": \"Node relations query function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeHasChildrenFunction\": {\n \"title\": \"Node has children function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeOpenedFunction\": {\n \"title\": \"Default node opened function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeDisabledFunction\": {\n \"title\": \"Node disabled function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeIconFunction\": {\n \"title\": \"Node icon function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeTextFunction\": {\n \"title\": \"Node text function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodesSortFunction\": {\n \"title\": \"Nodes sort function: f(nodeCtx1, nodeCtx2)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"nodeRelationQueryFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entities_hierarchy/node_relation_query_fn\"\n },\n {\n \"key\": \"nodeHasChildrenFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entities_hierarchy/node_has_children_fn\"\n },\n {\n \"key\": \"nodeOpenedFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entities_hierarchy/node_opened_fn\"\n },\n {\n \"key\": \"nodeDisabledFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entities_hierarchy/node_disabled_fn\"\n },\n {\n \"key\": \"nodeIconFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entities_hierarchy/node_icon_fn\"\n },\n {\n \"key\": \"nodeTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entities_hierarchy/node_text_fn\"\n },\n {\n \"key\": \"nodesSortFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entities_hierarchy/nodes_sort_fn\"\n }\n ]\n}", "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {},\n \"required\": []\n },\n \"form\": []\n}", "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"nodeRelationQueryFunction\":\"/**\\n\\n// Function should return relations query object for current node used to fetch entity children.\\n// Function can return 'default' string value. In this case default relations query will be used.\\n\\n// The following example code will construct simple relations query that will fetch relations of type 'Contains'\\n// from the current entity.\\n\\nvar entity = nodeCtx.entity;\\nvar query = {\\n parameters: {\\n rootId: entity.id.id,\\n rootType: entity.id.entityType,\\n direction: \\\"FROM\\\",\\n maxLevel: 1\\n },\\n filters: [{\\n relationType: \\\"Contains\\\",\\n entityTypes: []\\n }]\\n};\\nreturn query;\\n\\n**/\\n\",\"nodeHasChildrenFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node has children (whether it can be expanded).\\n\\n// The following example code will restrict entities hierarchy expansion up to third level.\\n\\nreturn nodeCtx.level <= 2;\\n\\n// The next example code will restrict entities expansion according to the value of example 'nodeHasChildren' attribute.\\n\\nvar data = nodeCtx.data;\\nif (data.hasOwnProperty('nodeHasChildren') && data['nodeHasChildren'] !== null) {\\n return data['nodeHasChildren'] === 'true';\\n} else {\\n return true;\\n}\\n \\n**/\\n \",\"nodeTextFunction\":\"/**\\n\\n// Function should return text (can be HTML code) for the current node.\\n\\n// The following example code will generate node text consisting of entity name and temperature if temperature value is present in entity attributes/timeseries.\\n\\nvar data = nodeCtx.data;\\nvar entity = nodeCtx.entity;\\nvar text = entity.name;\\nif (data.hasOwnProperty('temperature') && data['temperature'] !== null) {\\n text += \\\" \\\"+ data['temperature'] +\\\" °C\\\";\\n}\\nreturn text;\\n\\n**/\",\"nodeIconFunction\":\"/** \\n\\n// Function should return node icon info object.\\n// Resulting object should contain either 'materialIcon' or 'iconUrl' property. \\n// Where:\\n - 'materialIcon' - name of the material icon to be used from the Material Icons Library (https://material.io/tools/icons);\\n - 'iconUrl' - url of the external image to be used as node icon.\\n// Function can return 'default' string value. In this case default icons according to entity type will be used.\\n\\n// The following example code shows how to use external image for devices which name starts with 'Test' and use \\n// default icons for the rest of entities.\\n\\nvar entity = nodeCtx.entity;\\nif (entity.id.entityType === 'DEVICE' && entity.name.startsWith('Test')) {\\n return {iconUrl: 'https://avatars1.githubusercontent.com/u/14793288?v=4&s=117'};\\n} else {\\n return 'default';\\n}\\n \\n**/\",\"nodeDisabledFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be disabled (not selectable).\\n\\n// The following example code will disable current node according to the value of example 'nodeDisabled' attribute.\\n\\nvar data = nodeCtx.data;\\nif (data.hasOwnProperty('nodeDisabled') && data['nodeDisabled'] !== null) {\\n return data['nodeDisabled'] === 'true';\\n} else {\\n return false;\\n}\\n \\n**/\\n\",\"nodesSortFunction\":\"/**\\n\\n// This function is used to sort nodes of the same level. Function should compare two nodes and return \\n// integer value: \\n// - less than 0 - sort nodeCtx1 to an index lower than nodeCtx2\\n// - 0 - leave nodeCtx1 and nodeCtx2 unchanged with respect to each other\\n// - greater than 0 - sort nodeCtx2 to an index lower than nodeCtx1\\n\\n// The following example code will sort entities first by entity type in alphabetical order then\\n// by entity name in alphabetical order.\\n\\nvar result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType);\\nif (result === 0) {\\n result = nodeCtx1.entity.name.localeCompare(nodeCtx2.entity.name);\\n}\\nreturn result;\\n \\n**/\",\"nodeOpenedFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be opened (expanded) when it first loaded.\\n\\n// The following example code will open by default nodes up to third level.\\n\\nreturn nodeCtx.level <= 2;\\n\\n**/\\n \"},\"title\":\"Entities hierarchy\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"widgetStyle\":{},\"actions\":{}}" } @@ -170,7 +170,7 @@ }, { "alias": "markdown_card", - "name": "Markdown Card", + "name": "Markdown/HTML Card", "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAYAAABJ/yOpAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAIABJREFUeJztnXl8E9Xax79pku4bLbuyVJGCQClgK2WnQAVFlgKCgvQqoiAKCO53ebkovF5fAVEvKiCIiEJBEES2Fig7CAUr+9qN0oWmadM2SbPN+0dsaNpM2pSCLPP9fPh86JkzZ54zk2fmnDO/eR6ZIAiCyWRCrVaj1+uxWCxISNyvuLm54enpSWBgIEqlEpnRaBRycnLw9PRELpff9AHq1atXB2ZKSPw1mM1mSktL0Wg0NG7cGIVara4z55CQuNuRy+X4+/sDoFarcdPr9ZJzSEhUwsfHB71ej5s055CQqIpcLsdiseD2VxsiIXEnIznInxiNRk6ePFltvXPnzqHVam+DRc4RBMHp9jvFzrudWjmITqdj165dLu2zefNmBEHg4MGDqFSqWpdXRq/X8/PPP9v+3rhxIzqdziXbALKysnj77berrffGG2+Ql5fncvt1SUZGBo8//jhpaWmidW7GTovFwpkzZ2pp3b2Fyw5y/vx5Jk+ezFdffVXjffR6PZ9//jkymYxPPvnEdvdztdwRmZmZvP/++2RkZJCVlcV7771HZmamq926q2jYsCETJ06kcePGt6T9kpISJk6ceEvavttQuFLZbDazYsUKnn32Wb755psa7ZOYmMixY8cAWLJkCRkZGfz+++8ALpX379/fYfs5OTl06dKFxMREFAoFnTt3Jj8/n9atW7N+/Xr27t2Lj48PsbGxdOnSBYDDhw+ze/durl+/jkKhYMaMGXZtGo1GvvnmG4YOHUqTJk1ISUlh7dq1yOVyNBqNrd6lS5f4/vvvkclkjB07llatWrF27Vr69OlDgwYNACgoKCAxMZGBAweyZMkSrl27ho+PD88++yxt27YVPW9i7XTo0IEtW7YAoFKpeOCBB2z7iNl5/vx5Vq9ebVvbnzRpEn5+fmRkZLBixQq0Wi2xsbFERERw9epVvvvuO0pLS5k3bx4AI0eOpEWLFuIX+R7GpSeIXC5n7ty5tG/fvsb71K9fH7VaTXh4OGazmZCQEOrXr+9yuRgFBQX06tWLI0eOcOjQIXr16sX169cBaNeuHa+99hp9+vRhypQplJaWArBs2TJ8fHwYP348o0aNIjAw0NZeWVkZ06dPR6lU0qRJE7Kzs5kyZQq9e/emV69eGI1GAPLz85kwYQLdunXj8ccfZ8KECahUKn777TeuXLlCbm4u2dnZpKenc+TIEQoKCvjll18YP348nTp14uWXX7a15Qixdho0aEBUVBT79+8nOzvbVl/MzuzsbF566SW6du1KXFwcv/76KyqVCpVKxYQJE+jatSuxsbG8/fbbZGVl4e/vT2RkJO7u7kRFRREVFWV3fu43XHqC1Ibw8HDWrl1LTEwMeXl5dO/enfDwcACXyx1RWFiIj48PgYGBmM1mfH19UavVADRt2pTDhw9jNpvx9/fn2rVrPPLIIwA89thjVdrVarW89NJLxMbGMnz4cAB27dpFdHQ0AwYMACA4OBiAhIQEevfuTUxMDAD79+8nMTGRpk2bkp2dzfbt29HpdPTs2ZPmzZsD4OXlRceOHenYsSOLFy8mKyuLli1bOuyXWDvlN5GAgAC7+mJ2JiYm0q9fP5544gmbDeX1mzVrhtlsRqVSERISwpEjR4iNjSUyMhKlUkm3bt3EL+x9wi13kP/+978kJiZy+fJl8vPz8fDwQKlUArhUPmXKFIftFxcX06hRI95++20EQWD37t2o1WrUajUjR45k0KBBBAcHo9PpMJvNTm01m83o9Xq7OYxWq8XPz8/hccvfuAIEBASg0WgICQkhMzOT1NRUDAYDqampPPTQQ1X29/b2Rq/Xi9pS03aqs9NgMNicoiJqtRqTyWTra1RUFA8//LBo+/crt3yZ9/nnn8fb25vFixcTHBzMJ598wosvvuhyuRilpaUolUqCg4OpX78+SqUSrVbL5cuXadCgAW+++SYvvPACTZo0qdZWPz8/Vq5cyZkzZ2zj7/DwcPbs2VNlZaxjx44cPHgQo9GIwWDgwIEDhIeH065dO9avX0+3bt3o0aMH8fHxtGnTxuXzVl07vr6+FBQU2P4WszMyMpJt27Zx9uxZzpw5Y5ubdOrUiaKiIsaOHcvEiROZOHEiHTt2BKzOW1pa6tSB7xdcfoL8+9//5sSJE6hUKkaOHMmsWbOczkmysrJ45JFH8PPzIy8vjzZt2iCTyUhLS3OpXAytVotCcaMbCoWC0tJS2rdvj5eXF0OGDKF+/fqkpqbWSFLj6enJZ599xrhx4/j5558ZNmwY0dHRDBo0iIYNG5KXl4dCoeDxxx/n8ccfZ9CgQVgsFgYOHEhERARms5mSkhKGDx+OyWRi+fLlPPTQQy6vrD300EMO2yln6NChzJo1iy+//JJp06bRp08fh3Z26NCBN954g//85z/4+vpiNBqRy+VERETwxBNP8MQTT9CkSRNKSkrYtGkTCoUChULB008/zVNPPUVAQADTpk2jd+/eLtl/ryBLS0sTKg4VbpY7Tc1bVFREWVkZ9erVsw3haoPBYKCwsLBKO1qtFplM5nAYc6vR6XTodDqCgoJE7bRYLJhMJtzd3cnOzmbYsGHs37/f1ofyOYij86PRaJDJZA6HbvcD6enpt34O8ldTeTJbW9zd3WnYsGGVcm9v7zppvzZ4eXlVcczKdubk5DB+/Hjc3NxQKBT8z//8j50jyOVyh/0CqMsb593KPe8g9ztNmzYlMTHxrzbjrkXSYklIOMHlJ8jRo0c5ePAgAQEBDBkyxG78KyFxr+HSEyQ3N5cff/yRsLAwioqKmDlz5q2yS0LijqDWq1hGo5F+/fqRlJSEm9sNP7vTVrEkJGpLenp67ecgiYmJPPbYY3bOISFxr1GrVaxjx46xbNkyvvjii7q2R0LijsJlBzl37hxz585l/vz5NGrU6FbYJCFxx+DS+EgQBD744AP++c9/iqpQJSTuJVx6guTm5pKWlsacOXNsZW+88Qbdu3evc8MkJO4EXHKQxo0bc+DAgVtli4TEHYe0BCUh4QTJQSQknHDPOsjdFudKjOriX0ncWlxyEIvFwp49e/jiiy/47rvvKCwsrPG+Z86c4dSpU9WW3ytxrmraX2fUJP6VxK3FZQc5deoUbdu25dq1a7z//vvV7mM2m8nIyOD48eMcO3aMq1evYjKZRMvv9jhXrvbXGbc6/pVE9bi0iqVQKGzBEzp16sSYMWOq3SczM5OpU6fi5eWFIAisX7+ehQsXIpPJHJbf7XGuXO1vSEiIw/N29uxZ0fhXycnJrFu3Dp1OxyOPPCIa0KIcsfMmUT21moPs2LGDjz76yGkwhXJatmzJ0qVL8fDwwNvbmyVLlhASEiJafrfHuXK1v2KIxb/S6/W89tprDB48mKlTpxIREVHtNRA7bxLVUysHuX79OgaDgT/++KNGKdu2bdvG4MGDeeqpp9i+fbvT8opxrnx8fKrEuUpNTbWLc1VOeZyriIgIPD09gRtxrvr378+ECRMA+/hR/fr1cxjnauDAgfTs2dMuztXXX3/NZ599RnZ2dpU4V8OHD8fX15esrCyX+ytG/fr16datW5VPht3d3alXrx6HDh3Cw8ODyMjIas+/s/Mm4ZxaiRXHjh3Lc889R1xcHCdPnrSFixFj/PjxNS6/F+JcudJfV3Fzc2P16tWsXr3a9sT717/+JVq/NudN4gYuT9LLMRqNaLXaOg9acK/GuaotleNfCYKAp6cnL7/8Mps3byYhIYGMjAzR/Wtz3iRu4NITJDU1lffee48GDRqQlZVF//79baE864p7Nc5Vbakc/+rRRx9lzJgxPPDAAxQVFdGmTRuaNm0qun9tz5uEFZe/KDQYDOTn51O/fn3c3d2rbL/VXxTey3GuxKgc/8pkMqFSqfD29q5xzKq6Om/3E+np6fd+4DgJidpyU5/cSkjcD9wWB8nJyWHdunWsW7eOEydOANb3DgcPHuTgwYN2L+vKqakGqaaaq5vlTrOnptxp9txt1NpBLl++zKFDh2pU98KFC8THx9v9yK5du8a2bdt49913uXDhgl19VzRIzjRXdZVr706zxxVqqkmTcEytHOTq1avMmDGDtWvX1nifZs2aMWrUKDp16gRAWFgYs2fPdvhOoa40SHWVa+9Os0fi9uHyi0Kj0cjcuXOJi4tj//79dW6QMw2So1x7YH0Z9u677+Lh4cHYsWNp3bq1aK693377zaG26plnnnGYs+9W2yOW+y85OZkNGzYQFBRk04xNnz4dPz+/OtGkKRQKtm/fzrhx4wBYvnw5w4YNQ6FQ8OWXX5Kbm0tQUBDjxo27b/MTQi2eICtWrGDAgAFOdUQ3g7McfI5y7QEolUpGjBhBeHg4L730EiaTSTTXnpi2Sixn3622R4yDBw/SpEkT1Gq1TTu1evVqoG40aSqVig0bNti2x8fHU1RUhEqlYsuWLcTFxdGmTRvGjRvnNA33vY5LT5CcnByOHTvGokWLSElJuSUGieXgE8u1B9a3zREREURERPDVV1+RlZVFixYtHObaE8v95yxn3620xxkNGzYkMDCQ4uJiWrZsyfHjx219uNnci87w8vIiLCyMsLAwjh07RmJiIqNHj66RzfcaLjnIxo0bUalUTJ8+nZKSEq5du8aaNWtuy8kTy7VXGV9fX6cfWIlpq7Kzs13K2VdX9tRk/4oZtupKkyaXy6v9HgWsN6yioqJa23+345KDjBkzhsGDBwPWL+M2bNhgu4PWlopq3crlFTVIkZGRTJ06lSFDhiAIgsOl4cpUzLVXrvBt164dCxcu5LnnnsNkMrF69WqWLl1K48aN+fXXXxk7dqxDfdmtsqc6hg4dCliVwGCvrQLYunVrtW2Ua9KmT5/OvHnzmDlzJg0bNiQ7O5uSkhJ8fX3t6ptMJiwWCxaLhUOHDlWZy9xPuOQgAQEBtqFGXl4enp6eN51Du1xrtGjRIluuvYrlFXPwOcq15+zu6SjXXo8ePRxqq+RyuWjOvltpj6u5/+pSk/bcc8/x1FNP0bhxY/Lz81EoFJhMJnJzc3nyyScxGo1ERUXd1+mgb4vUZO/evWzcuNG2elMZrVaLXq+vkmukogapulx7znAl156znH1/hT1i1JW2Sq/XU1paSmBgIHK5nLS0NCZPnsxPP/2E2Wy+b/MTwm3MUejm5sbhw4cZPXo0MTExto+XyvH29nY4rKmYg6+6XHvOcOUG4Cxn319hjxh1lXvR09PT4XDvr8y9eCchiRUlJES4LWLF6jRXdwMnTpywaclycnKqbC8uLrZ9N1+ZzZs3o9Pp7nhNVLmdNS0vp7p+3aq4XrfrfLrsIOfPn2fjxo22f2VlZU7rO9Nc3U0IgkB8fHyVPqjVauLi4mzvKCqSk5PDvHnz8PT0rJVG63Zptyra6azckT3O+nUr43rdLo2Zyw6ya9euGgc+A+eaq7uFTp06MWrUKJo1a1Zl2+zZsxk8eLDD5e7t27cTExNj9x7DEWIardul3RKzs3K5q/bcC3G9XJ6kl5aW0rNnT3r16nXTB3ekKdJoNA7jTYFj7ZNer3eoKapXr56oZslRO35+fg61WM64dOkSFy9eFF2dS0hIYNq0aba/XdFoyeVyh+VBQUGiWiln8bISEhIAGDBgQLV2OioXs1OsX2IaNlevr5+fn2i/NBoNs2fPxmAwMGrUKFvwEEfxzaB28cFcfoIUFBSwd+9eEhISbDGlaosjTZFYvCkx7ZOYpkisfWftONJiOSMxMZEnn3zSYZ5GlUpFeno6nTt3tpW5otESKxfTSlUXL2vZsmUsXbq0RnY6KnemJXPULzENm6vX11m/jEYj3bt3p1evXkyZMoWcnBzR+GZiv4fqcNlBnn/+eSIjI0lKSmLSpEk35SRi8ZocxZuqqH0KCwurkczDUfti7YhpsZyRlZVli5FVmYSEBPr27Wv3Eq9cozV8+HC8vLzIysqy/fDKNVrlsbDEysvPT1hYGCNGjKBHjx4kJiZWGy9rwYIFfPrppzWy01G5M3sc9Ussrle5/TW9vs76FRwcTL9+/YiJiSE6Oppdu3aJxjeD2sUHc9lB2rZtS0xMDHPmzMFkMnHu3DlXmwCsj+Vhw4aRkpJCdna2qKaoPN6UmPZJTFMk1r5YO2q12qbFyszMrFaLBdYLLbbCs2PHDofDmXJuVqNVTrlWqjxelr+/PxMmTGD27Nl29Ro3buww5I+YndXZL4ar/aru+lbXr3L8/PwoLS0VjW9W099blePXuCd/Uh4by2AwoNVq8fDwqNF+lTVXrsZrioyMZNu2bZw9e5YzZ87YlowraooqIta+WDudOnWiqKiIsWPHMnHiRCZOnFhtQLw2bdrYPiGuiEaj4dy5c3Tt2rX6E4O9Rqsm5eVaKZPJxKFDh2jfvn218bJ+/PFHVq1aVSM7xcrF7HFGZQ2bGGLXpSZxwPR6Pfv27SM8PFw0vllt44O5NEnPz89n0qRJNGzYkGvXrhEdHU3r1q1rtG9lzVXXrl1d0hR16NDBofYpICDAoaZITLPUpk0bh+1EREQ41WI5YsCAASxYsICrV6/y4IMP2sp37txJjx49avxmXUyj5ai8RYsWDrVSeXl5TuNlbdu2DYvFwtixY6u1U6xczB5nVNawiSV/Fbu+169fd9ivnJwc8vLyGDt2LFlZWQwZMsQ2P3EU30yv19cuPlhaWppQUFBQ4385OTnCyZMnhezsbIfbnVFaWiqoVCq7ssLCQiE3N1cwGAxO9zWbzUJZWZkgCIJw7do1ITIy0m4fnU4n5OfnCyaTyWn71bVjMplE7ZkxY4awZ88eu7K1a9cKI0eOFDQaja1s0qRJwo4dO5z2xxFFRUV27TgqT01NFQYOHCiUlpZWqWs0GoWcnByHbWi1WkGr1dqVidlZnf1idoqh1WqrXPfKOLsuYv0yGAxCbm6ubb+KlJaWVumvINT89yYIgpCWlia4vMzr7u5u99mpKzjSXNVUU1Sd9klMU1S5/eracaTF+uabb9ixYwdXr16t8sHRyJEjKSwsZOvWrTzzzDNotVqOHz/O/Pnza9SviohJfhyVO9JKKRQK0dz1lcf3YnbWxH5XpUkVNWxiOLsuYv1SKpWiujkxLZmrGjZJiyUhIcIdFTiuprkChVpqe8Q0Rbc6R2HF4+bl5VVZTJC4s6mVg1gsFo4ePcrmzZvrzJCa5AqsrbZHTGtU0+PWlsrHPXjwIHFxcXetaPN+xGUHyc3NZcKECWzatOmm36S7Sm21PTXVRNU1lY87bNgwevTowZw5c26rHRK1x+VJ+qxZsxg9ejQDBw6s8T6O4jU1btxYNFegI5zFpxLT3pRTWWvkSo5CsL4X+OGHH7h48SIeHh5MnjyZZs2aVZsr0JHG6fXXX2fw4MGkpaWJLnlK3Dm49ARJT0/n8uXL5OXl8e2339Z4qOMoXpNYrkAxxLQ9zrQ3UFVT5GqOQr1ez3PPPYdWq2X8+PE8/fTTBAQEVKt9EtM4KRQKnnrqKZv8QeLOxqUnSFpaGg0aNKB58+ZotVqmTJnCihUrqF+/frX7Vo7XVDFXIGDLFSiGWLysitobgP3799vFcaqsKRI7rlg7DzzwAIGBgVUie1gsFptG6Nlnn62ifRLTOIE1sWlycrLT/krcGbj0BFEoFDz44IP06dOHJ598kvDwcIdSi5oglivQVcS0N+VU1hS5mqNQrVY7vAFUpxFypmXS6XTSN993CS45SKtWrTh//jxlZWUIgkB2drYtxq2riOUKLMeRdgiqanvEtDfgWFPkao7CsLAwjh49WkX6LjjRCFWnxUpJSbmteQ4lao9LQ6xGjRoxdOhQ4uLi8Pb2JiQkpEqYy5oSERHhMFdgOY60Q+A4PpUj7Q041hSJHVcsRyHAm2++yZgxY2jUqBEGg4EZM2Y4zRXoTIuVnZ3NgQMH+Pvf/16r8yZxe6nVm/TyIASO9nP1TbpYrsDyO7wjiULlnH3gOLfg5MmTiY2NdTjUcTVHoSAI5OXl4efnZxseieUKFDtueYzc0aNH2yImSty53NM5CrVaLX379iUpKem2JuR0dtz4+HhKS0t54YUXbps9ErXnnnYQCYmb5Y7SYklI3IlIDiIh4QTJQSQknKAA6lRdKilVJe4lFMB9naRRQkIMaZIuIVENkoNISDhBchAJCSdIDiIh4QTJQSQknCA5iISEEyQHkZBwguQgEhJOkBxEQsIJkoNISDhBchAJCSdIDiIh4QTJQSQknHBHOsj58+dZsmQJV69erVH97du3s3z58ltsVd2Rnp6OwWBwuK2wsJAlS5ZIgeXuEGrlIFFRUURGRrJ69eoq286fP09kZCSRkZGcPHmyVkadPHmSefPm1Ti06YYNG/jss89qdazbTUZGBk888QT//e9/HW5XqVTMmzePQ4cO1cnxLly4wJUrV+qkrfuRWjmIRqNBo9Gwdu3aKts2bNhg216TLKL3G02bNmX69Ok8/fTTt+V4r7zyCu+///5tOda9iMvR3csJDAzk9OnTXLhwwZbI02Qy8csvv1CvXj27jLZgjc6+b98+wJrRtDzgXFZWFgcOHCAyMpJDhw7RrFmzKsfKzMy0bYuKisJisZCYmMiVK1fo0qWLQ/sOHz5McnIywcHB9O7d25bVdOPGjQQFBdGzZ08ADhw4gEwmo1u3bgDs3buXwsJChgwZwk8//UTz5s3x9/dn7969+Pn5MXTo0CrhfFQqFTt37iQiIoKQkBAsFgvr1q3j8ccfp0WLFpjNZn766ScefvhhWrduTVBQkF1kx/L87W5ubrRt27ZKXzIyMti1axfu7u7ExMSwa9cuwsLCbNEZCwsL2bJlCxqNhvDwcLp27Yper2fTpk1otVpUKhXx8fEMGTLEYY4UCSekpaVVm8ywMo8++qgwc+ZMoUuXLsJHH31kK09MTBRCQ0OFf/3rX0JoaKhw4sQJQRAEYeXKlUKbNm2EJ598Uhg4cKAQGhoqrFy5UhAEQdixY4cQGhoqdO/eXQgNDRXmzJkjrF27VggNDRX27dsnqFQqISYmRoiKihLS09MFQRCEt956SwgNDRW6desmdOzYUejcubMQHh5us+Of//ynEBoaKkRHRwtdunQRunTpIhw6dEgQBEGYMGGC0L9/f0EQBMFisQi9evUSevbsKVgsFkEQBCE6Olp4+eWXBUEQhPDwcKFPnz5C586dhd69ewuhoaFCXFxclfNRUlIitGvXznYufv/9dyE0NFSYPXu2IAiCcObMGSE0NFRYs2aNkJaWJoSGhgqffvqpIAiCcPHiRSEyMlJo166d0KtXL6FLly5CaGio8Pnnn9va6ty5s9C+fXuhV69eQrdu3YTQ0FBh8eLFgiAIwqVLl4Ru3boJnTt3FgYMGCCEhoYKn3zyiZCfny/0799fePTRR4WwsDChf//+glqtdvla38+kpaUJtZ6ky2QyBg0axKZNmzCZTAD8/PPPhISEEBoaalf3+PHjjBo1is2bN/Prr7/SqlUrvvvuO7s6bdq0YevWrUydOtVWptVqmThxIvn5+SxdupTmzZvzxx9/sGnTJoYOHcr+/fvZu3evXYTFw4cPEx8fz/jx49m5cyeJiYkEBQXx97//HUEQ6N69O5mZmeTm5nLmzBny8vLIy8vj7Nmz5OXlkZWVZXuagDWpZ2JiIklJScTExHD48GGKiorsbPfx8SE8PNw2sd69ezcymYykpCQAW4DvHj16VDmPX3zxBSUlJcTHx7Nnzx7eeecdu+0LFizAbDazadMm9uzZw2uvvWa3fc6cOZjNZrZu3cqOHTuIi4tj2bJl6PV6EhISaNiwIW3btiUhIYHAwEDxCyrhkFo7iF6vJzY2FpVKZRuW7Nmzh5EjR1JWVmZXd/78+YwYMYKVK1fy6aefUlZWZpfDA2D48OGEhITg6+trK/voo484ffo0c+fO5dFHHwXgjz/+AOCZZ55BJpPh7+/Pww8/bNunfBg3btw4wDoUHDJkCFlZWaSnp9O9e3cAkpOT2bVrF23btqVVq1bs3r2b48ePA9jqgDVgd3kwvPKhZH5+fpXzERUVxenTp9FqtezatYuhQ4eSlZXFhQsXSE5OJiQkxC5veTkpKSl06NDB1r+K+UQEQeD3338nKiqKkJAQwBpkuxyDwcDhw4dp2rQpSUlJxMfHIwgCZrOZs2fPVjmWhOvU2kG0Wi2dOnXioYceYsOGDWzatAmz2czQoUPR6/V2defOnctzzz1HcnKyS0k4c3NzkcvlbN++3VZWngRTLJ1v+di+4vby/6tUKlq3bk3jxo1JTk5m9+7dREdH069fP5uDNGrUqEqGqprQo0cPzGYz27dv58KFC7zwwgs8/PDDtnYrOl1FSkpKRO/sJpOJsrIy0b6WlJRgsVjIyclhzZo1rFmzhuTkZNq1a1frZKcS9tR6kl5+AWJjY1m4cCEXL16kT58+1K9f3271SqfTsWrVKoYMGcL//u//Atal4IopDMR46623UKvVfP311/Tu3ZuhQ4faJtupqam2H3LFH0N5hJbLly/b7sYXL15EJpPZFgCioqLYtWsXOTk5fPjhh5hMJhYvXkxhYaHoD7k62rdvT0BAAJ999hkPPPAAoaGh9OvXj3Xr1pGdnS3abtOmTUlNTUUQBGQymV1flEolDRo0IDU11VZWcXtQUBB+fn5Vhqxms9lh4h4J17npF4XDhw9HEATS0tKIjY2tsl0ul6NUKjl58iRHjhxh+fLlHDx40DZvcUarVq2YOnUqHTp04MMPPyQrK4u+ffvi6+vL/Pnz2b17N99++y0HDhyw7TN48GD8/Pz44IMPOHjwIPHx8WzcuJHevXvbks5369aN7OxsGjduTNu2benQoQONGjXi6tWrtXYQuVxO165dyc7Opl+/fgD069ePzMxMFApFlRRtFe1NT0/n448/Zu/evcydO9du+5AhQ0hJSWHhwoXs2bOHTz75xG776NGj+e2335g3bx7JycksWbKEQYMG2W5zgRuiAAASx0lEQVRA/v7+pKenk5SUVOXJLlE9N+0gwcHB9OrVy7acWhl3d3c+/PBDcnJyiIuLY+3atURERFBWVmaXa1AMuVzORx99hNFo5K233sLHx4f58+dTWFjI5MmTWbdund2PLzg4mIULF6LVannxxReZNWsWPXr04KOPPrLV6dGjB25ubkRHRyOTyZDJZERHR+Pm5kZUVFStz0W5c0VHRwMQFhZG48aN6dSpk93cqiLleQ+/++47Jk+eTPPmze22T548mQEDBvD111/z6quv2pZp3dysl+7111/nb3/7GytXrmTs2LF8/fXXDBs2zLZwMXbsWDQaDZMmTaoy75OoHllaWppwOwLHmc1mCgsLq81FWFMEQUCtVtutYFWmsLAQpVKJj49PnRzzVlJaWopcLq/ynsJisaBWq3F3d0epVLJz505mzpzJggULGDRokK2e2WxGpVJVyXcC1rmK2WwWnctIOCY9Pb32cxBXkcvldeYcYF1mduYcwF21rCnmxD/++COLFi3imWeewd3dne+//54mTZpUWTKWy+W2IWRlxJ5eEtVz2xxEonYMGzaM3NxcEhMTMRqNdOvWjalTp9ZJAlSJ6rltQywJibsNKTavhEQ1SA4iIeEEyUEkJJwgOYiEhBMkB5GQcILkIBISTpAcRELCCZKDSEg4QXIQCQknSA4iIeEEyUEkJJzgsoMUFRUxb948Fi9eXGVbecC3ip/I1gSdTkebNm1Yv36903plZWW0adOG+Ph4l9q/GZKSkkhISKjzdiPnFJBRYMZkho+3laIzOP9E9pt9Ov75c0md21GZY2lGNv5eVm29fvPUnMmu/qO3ux2XHUSj0bBkyRLmz5/P+fPn7bYtXryYJUuWsGfPnjoz8K/Gw8MDDw+PW9a+TAY+HjJkstq3seaonvkJ2jqxx10hw0NxE8YAY5cWcfn6vRE0sNZDLF9fX37++Wfb32q1mqSkpCrfHly6dIn4+Hh+/fVX2yefKpWKbdu2kZGRwZo1azAajXb7nDlzhm3bttkCMBw9epQ1a9Y4jNX722+/sWrVKg4ePGj7Xvvw4cOcPn0asH4stH37diwWi63+yZMnyczMJCEhAZVKxbp169ixY4etTkWCg4PtvrNISUlh1apV7Nmzx2F9sAab+Pnnn21RJp0hk0GrhgoUbtYfZZlJYMvJMjallHG92MKe8/YxfE9fM7H6Nz2nr1nv3qeyTCSnmziVZeLQZSNpKjOnsm7c2Y+mGlFrredFaxDYde5Gexdyzfx4RM/hKzfOv7+XjAcCb/ws0lRm4o/qOZpm5EKumdT8Gz98gwm2nTLw0/EyivUCZgtsP20gLd9M0nkDWYWOz8/dRK0dpH///nYxsX755RcaNmxoi/YH8MMPPzB8+HASExNZsGABY8aMwWg0cv78eaZPn86oUaP4+OOP7QI5nzp1inHjxnH69Gm8vLxYvnw548ePZ/369bz00kt2NsyZM4eJEyeSkJDA1KlTmTFjBgBbtmyxBYjYuXMn06ZNs8UJnjFjBseOHePQoUNMmzaNuLg4NmzYwPTp0/n000+r9HPz5s1s3LgRgNWrV/OPf/yD0tJSFi9e7DCk5++//864cePIyckhJSWF2NhYuyiKlTGZBWasKUZvEhAEeGVlMWuPlXEpz8zk74v59y+ltroHLhlZcVBPdpGFF5ZrOHnVREGphSKdhdIygbxiC3kaC7M3l/7ZNkxdXcwvKdYh0+ErRlYdtt6kNv5exow1xRTpBT7fpbU9gZLOGfjhiLXOH1dNPLu4iNR8M2uPlfHSCg2JZ25cqw83l3Iyy0TC6TJeWanBIsDVAjNmC+RprDbd7dTaQaKjo9HpdOzduxewBo2LjY21i4nl4+PDp59+yuLFi/nPf/7DuXPnuHjxom37e++9R3Jysu1ruszMTF555RX69evHjBkzMJvNLFq0iPHjx7NmzRq7yB2XL19m5cqVzJ07l2+//ZbFixezdetWDh8+TI8ePTh58iQGg4GkpCQ8PT3ZvXs3GRkZ5Ofn277Gs1gsLFq0iFWrVjFo0CD279/vtM/79+9nzJgxvPzyy3zxxRcO41wBfPLJJ0yaNIlZs2bh4eHBqVOnanROj6QayVKbWRrnz4wB3rz1hLfd9taN5Hw80pc3BngT86g7h68Y6dXanYiWSkIbyRka7kHn5koyC8wU6QSOphlpFiS3PTWOphrp+YgSoxn+s7WUT8f4Mam3F1+N82fVYX2VedDSfTom9PDinUE+fDzSl07N7b+ve72fF2894c2C0X78cdVEmUlgQk8vvN1lDOvkQetGd39klZuKrBgTE8OGDRu4cOEC586dY/jw4XZ3y8cee4yEhASefvppZs6cCVi/vS4nLCzMrs3FixejVquZMmUKMpmMvLw8iouL6dq1K4DdUKd8CFUeKKFz5874+Pjwxx9/0LVrV0wmEydOnODAgQO8+uqrtvhU9evXt4t71ahRIwDq1auHVut8HP/iiy+ybNkyxo8fz5YtW5gwYUKVOm3btiUpKYlx48YxcuRIsrKynD5BKpJ63Uz7BxTI/7wqfl72c4EGfjcul5+nDJ2x6h1aIYfHQ5T8lmpk5zkDr/TyoqDEglor8Fuqid6h7lxVmynWC3y0tZSXVmh4Y00xFgGuFdkPia5cN9PxwRtO4e/p2B4vdxluMusQ7l6j1p/cGo1GRowYwYsvvoiXlxddu3aladOmdvOJN998Ex8fH5YtW0ZBQQFDhw512manTp0oLS3lH//4BytWrLAFia4cqRGs4WzAugIWGBiI0WikrKwMDw8P/P396dChA1999RXBwcE8//zzLFq0iF9//ZUePXogq+WMuHPnziQmJpKSksKPP/7Ixo0bq6yoLVq0iJycHJYuXYqnpycjR46scfveHjIMdbAw1Ku1O4cuGzlyxcjMAd6kZLrzy+9laA0CIfXl5GosKOQy/vW0D24VTkVDP/v7pbeHDMO9MdeuNbV+ggiCwGOPPUaTJk3YtGkTI0aMqFLn2rVrBAQEIJPJ2LZtG4DTlAixsbH83//9H6dOnWLp0qUEBgbSunVrfvjhB7Kzs9m0aZOtbufOnQkICGDJkiUUFhaydOlSBEGgV69egDW0z6FDh4iOjsbLy4tu3bqxb9++Wse9AmsMsP379xMeHs706dM5e/ZslfhemZmZNGvWDE9PTy5dukRGRkaN00B0bq4gOd3IVbX1Tn4srWbeonCzv3v3fETJ5j/KeKiBHC93Gf3auvP1Xi09HrFGO2nk70bLYDeOXDHyYD05Df3c2H/RiNzN/sYR2VLJhuN6BAF0BsG2MFAdSjnoHOcHuuu4qReFMpmM2NhY/Pz8bMHSKjJz5kx27txJz549OXfuHEC1SXFatWrFtGnT+Oyzz0hJSeHDDz8kLS2Nvn37snXrVttTxd/fnwULFrBr1y66du3Kt99+y4cffmiLYVsegLrcrv79+yOTyW4q7tWbb77JBx98wNChQxkxYgTvvPMOCoX9Q/iFF14gPj6e6Oho3n33XZo0aUJ6enqN2m8WJGdKX29GfVXIEwsK2XexZr+yrg8r2XvRyKvfFwPWoU+LIDn92roDEPagAk+ljF6t3W37fDzKjx+O6Hn680JiFhRyvcRiG9qVM7GXF9dLBPrNUzPiyyJk1Gw5um8bd17/UcOWk9W/T7nTueVBG8qHPjcTekYQBEpKSkQjeRQWFuLn53fbwm1qNBp8fHxEj2exWCgpKbENA11qWyfgqQSLAPsvGll2QMcPE6uPZ6U3ClgE8HZ3bfio0Ql4KHH47sNgsrZpNIOvh4wJKzQM7+TB0x2rfy9UqBXw85RVcbq7ifT0dCmqyV/Bf3drKSitOqG1CLDtVBlNA+V4KuBinpnwZkqaBf01v7Kraguns0y0qO9Gsc66jPxEew8UNTSnoZ8br/T2qr7iHYrkIHcgxXqBfRcN5JcIdH1I+ZcvlV7INZOcZsTLXUZMO3eXn1B3M7c1sqJEzfDzlPFkh1snbXGV1o3kf7mT/pXcxSNECYlbzx3hICVlAu3+pcJgqvsXTR9vK60zIZ/E/ccd4SASEncqLs9BivUCKZkmWtaXc/iKgcb+crq3UnIm28TvGSYebiin60M3wu9nFpg5kmrC2x2i27jjqZShMwgcumIkpL6cExkmYtq52x3jbLaJkjKBiJZKtp820DdUibtCRplJYM95IzHt3LlWaCG/xIJcBqeumWj/gIJ2TavvTmq+mWNpRvy93Ihu445Sbl3qPJll4uEGcvZfMhLsI6NPqLttzT+zwMzhP1+qNfJ3wyzAIw3l7LtopMMDCgK9rRUTzxro/rASL3errQcvGcnVWHispZJWDW+M4y/mmTmebqRNYwUKuVXC0SzIuv30NRN/ZJp4pJGcx1oqq9gvcXtx+QlyrdDM9DXFzP21lOwiC7N/KeHl7zQs2q1DrbXw7k8ltg9udp0zMGllMUU6C7vPGRm/TIMggKrUqmB9a20JZyt9dHMiw8Sr3xfj6yFDEGDGmmJK/lSFFusF3lxrfRmWnG7k1e81LN6n46rawoRvNSSccf5ibePvZUz70dre5pQyXv3eKkXPVJuZGV/MrE0l5GksfLxNyzf7rfqpC7lmRn9dxIVcM5v/KOOF5Rq2/vkCbM6vpaSrbrwlf/enElSlAjqDwPNLNey5YKRYL/DCcg1HU60SnEOXjcR9U0RmgYXlB3RMWlnMwcvWbT/+puf99SUU6QX+b7uWr/bUTMMlceuo1SqWuxwWPuuHUg4h9eUsSNCy4416yN0gwMuNfRcMDA33wFMp49Nn/XikoRyLAFFzC8gqNAPWO+6SOH/qectsDnAqy8wba4pZOMaPtk0UVJeHskWwnIVjrC8PQxvLWbJXx4BH3UXrB3rJ+Pw5P1oEy3nucYHHPihAo7MeRCaDec/44eMho0WwGz8dL+Olnl4s269jTKQnU/tZlbXvr6/+q75Sg8DfunvaVqP0RoGEswYiQpR8vUfHtP7ejI6wJsp5YbnGVmdBgpYNUwJ5INCNEZ09GLSwkIk9ve7ql213O7VyEA+FDOWfIwZ/TxnBPm62i+jjIUP7p16xfVMFXyZpOXXNRJkR9CYBnRG8lKCQy6jnbb+mPm11MV0fUhLevGZm+Xjc2L9TcyWzNpU6qQ0dHlTw3906zueYMJhAwGoTWN9Al7fn6yGzSb+v5JsZ1P6G0/l5Vv8eoL6vG0q5jIkrNJSUCeRqLPT8Uwd1Jd9MeLOqCtkr+WYMJoH/2XjDAQ0m68u5JgGSh/xV3NL3IHO3lNLQ343lfwtAIYdeH6ud1p8+wJtFu7UknDHYngQ1Fd5qDQJeSueV/7GhlE7NFbz/ZAByN+j47+pz9nm7iytaZVidrDKnskx8sr2Ub18MoEmAG0v26riqNt9oz4Hmz9tdhqdSxqwh9pmmGvhKzvFXckvPfmaBmRbBchRyOJ5uQqOzYDKLj5ueDnNnwWg/Zv9SylW1GZnMejcu/7654qek1vYttuHZhuN6Ordw7u8ZBWZCGsiRu8G+i0bMFutXd86IbKlkw4kyzBbr57B/XL1hQwM/N678aduFXLNtmTpTbcHXw42Gfm7ojQKHrxgxmsvbU7D+hHUOo9EJXMi1bmhWT049bzdSMk08WE9Ofd9yha1z+yRuLbf0CTKpjzfv/lTMV0lamgdZL3pmgYVHm4pf9bAHFfytuycz4ktY9VIAU/p68foPxQR4ufFQA/s3ujIZvLhcQ2mZgEwGX45znpbstWhv/vlzCf+7RUabxgoCvGRkFpjxdTJsGt/NkzdWF9N/nhoPpQz/Ch8xvdTTk3d+KmHJXh2NAtzw/PMJ1jdUSfxRPX0/UaNwg3ZNFWT++QR5rZ83r/1gbc/LXYZCbn0Syd1g3mhf3llXwtd7dBTpBJ6P8rypYA4SN88t12KZLdbhT03G7mKUmawBASrqgH5JKeOXlDIWj/dHoxPsfrjOMJmt8w5fj5rVL39ymC3WOc/UH4vp+YjSNsk2mUFndNw/jU7Ax8Ne0aozCCjk1jmOv5eMkV8W8Xo/L3pXkKIX6QS8lNYIIxJ/HbXSYn2w2flE+HaRpjKTnm++5fbkFFk4kWkkJFhOqUHgWqGFet5uXMit3XGvXDdz+bqZ5kFy1FoLRTqBpHNG9l4wOqz/WEul3SKBxO3FZQf55+A7I+f4pTwzl/LMDLwNP57L1838lmrEXSEj5lH3m3oaApzOMnEi00SAl1Uhe7NxqCRuHZLcXUJCBCnLrYRENUgOIiHhBMlBJCScIDmIhIQTJAeRkHCC5CASEk6QHERCwglubm5uNQ6NKSFxv2A2m3Fzc8PN09PTLuK6hISENfGSp6cnboGBgWg0GjQajfQkkbjvMZvNaDQaiouLCQoKQiYIgmAymVCr1ej1etG0YhIS9wNubm54enoSFBSEXC7n/wF1srhlxTIbmgAAAABJRU5ErkJggg==", "description": "Renders markdown/HTML using configurable pattern or function with applied attributes or timeseries values.", "descriptor": { @@ -180,10 +180,10 @@ "resources": [], "templateHtml": "\n", "templateCss": "#container tb-markdown-widget {\n height: 100%;\n display: block;\n}\n\n#container tb-markdown-widget .tb-markdown-view {\n height: 100%;\n overflow: auto;\n}\n", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.markdownWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.onDestroy = function() {\n}\n\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown pattern (markdown with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n },\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\"\n }\n ]\n}\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.markdownWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n },\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\"\n }\n ]\n}\n", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"},\"title\":\"Markdown Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown/HTML card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"},\"title\":\"Markdown/HTML Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" } } ] diff --git a/ui-ngx/src/app/core/api/alias-controller.ts b/ui-ngx/src/app/core/api/alias-controller.ts index 5f7474a31b..68e12411c1 100644 --- a/ui-ngx/src/app/core/api/alias-controller.ts +++ b/ui-ngx/src/app/core/api/alias-controller.ts @@ -323,6 +323,9 @@ export class AliasController implements IAliasController { } resolveDatasources(datasources: Array, singleEntity?: boolean): Observable> { + if (!datasources || !datasources.length) { + return of([]); + } const toResolve = singleEntity ? [datasources[0]] : datasources; const observables = new Array>(); toResolve.forEach((datasource) => { diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 5481af9255..d9136c86e2 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -387,7 +387,7 @@ export class WidgetSubscription implements IWidgetSubscription { } private prepareDataSubscriptions(): Observable { - if (this.hasDataPageLink) { + if (this.hasDataPageLink || !this.configuredDatasources || !this.configuredDatasources.length) { this.hasResolvedData = true; this.notifyDataLoaded(); return of(null); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 143b1743c7..a3c748c521 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -873,6 +873,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC if (revert) { this.dashboard = this.prevDashboard; this.dashboardLogoCache = undefined; + this.dashboardConfiguration = this.dashboard.configuration; } } else { this.resetHighlight(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts index 67acd1e04b..d1645e3f4c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts @@ -19,7 +19,7 @@ import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models'; import * as moment_ from 'moment'; -import { DataKeyType } from "@shared/models/telemetry/telemetry.models"; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { ComparisonDuration } from '@shared/models/time/time.models'; export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph'; @@ -466,7 +466,7 @@ export function flotSettingsSchema(chartType: ChartType): JsonSettingsSchema { schema.form.push({ key: 'tooltipValueFormatter', type: 'javascript', - helpId: 'widget/lib/tooltip_value_format_fn' + helpId: 'widget/lib/flot/tooltip_value_format_fn' }); schema.form.push('hideZeros'); schema.form.push('showTooltip'); @@ -516,7 +516,8 @@ export function flotSettingsSchema(chartType: ChartType): JsonSettingsSchema { }, { key: 'yaxis.ticksFormatter', - type: 'javascript' + type: 'javascript', + helpId: 'widget/lib/flot/ticks_formatter_fn' } ] }); @@ -531,11 +532,11 @@ export function flotSettingsSchema(chartType: ChartType): JsonSettingsSchema { schema.form.push(chartSettingsSchemaForComparison.form, chartSettingsSchemaForCustomLegend.form); schema.groupInfoes.push({ formIndex: schema.groupInfoes.length, - GroupTitle:'Comparison Settings' + GroupTitle: 'Comparison Settings' }); schema.groupInfoes.push({ formIndex: schema.groupInfoes.length, - GroupTitle:'Custom Legend Settings' + GroupTitle: 'Custom Legend Settings' }); } return schema; @@ -981,13 +982,15 @@ export function flotDatakeySettingsSchema(defaultShowLines: boolean, chartType: }, { key: 'pointShapeFormatter', - type: 'javascript' + type: 'javascript', + helpId: 'widget/lib/flot/point_shape_format_fn' }, 'showPointsLineWidth', 'showPointsRadius', { key: 'tooltipValueFormatter', - type: 'javascript' + type: 'javascript', + helpId: 'widget/lib/flot/tooltip_value_format_fn' }, 'showSeparateAxis', 'axisMin', @@ -1012,7 +1015,8 @@ export function flotDatakeySettingsSchema(defaultShowLines: boolean, chartType: }, { key: 'axisTicksFormatter', - type: 'javascript' + type: 'javascript', + helpId: 'widget/lib/flot/ticks_formatter_fn' } ] }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts index 9cca7e4a31..e96f775007 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts @@ -96,6 +96,8 @@ export class MarkdownWidgetComponent extends PageComponent implements OnInit { data: [] } ]; + } else { + initialData = []; } let markdownText: string; if (initialData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts index 7ddcaa0764..9f7da7a747 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts @@ -491,6 +491,9 @@ export class WidgetComponentService { if (isUndefined(result.typeParameters.dataKeysOptional)) { result.typeParameters.dataKeysOptional = false; } + if (isUndefined(result.typeParameters.datasourcesOptional)) { + result.typeParameters.datasourcesOptional = false; + } if (isUndefined(result.typeParameters.stateData)) { result.typeParameters.stateData = false; } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 4c0f2ad397..7351f9985a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -894,7 +894,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont }; } } else if (this.widgetType !== widgetType.static && this.modelValue.isDataEnabled) { - if (!config.datasources || !config.datasources.length) { + if (!this.modelValue.typeParameters.datasourcesOptional && (!config.datasources || !config.datasources.length)) { return { datasources: { valid: false diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index bf929637c8..687566afa7 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -152,6 +152,7 @@ export interface WidgetTypeParameters { useCustomDatasources?: boolean; maxDatasources?: number; maxDataKeys?: number; + datasourcesOptional?: boolean; dataKeysOptional?: boolean; stateData?: boolean; hasDataPageLink?: boolean; diff --git a/ui-ngx/src/assets/help/en_US/widget/config/datakey_generation_fn.md b/ui-ngx/src/assets/help/en_US/widget/config/datakey_generation_fn.md index 3dbece51c6..b73ec7bfe8 100644 --- a/ui-ngx/src/assets/help/en_US/widget/config/datakey_generation_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/config/datakey_generation_fn.md @@ -57,3 +57,6 @@ var index = Math.floor((time/3 % 14000) / 1000); return lats[index]; {:copy-code} ``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/config/datakey_postprocess_fn.md b/ui-ngx/src/assets/help/en_US/widget/config/datakey_postprocess_fn.md index 6fd0cf867f..acab47c45e 100644 --- a/ui-ngx/src/assets/help/en_US/widget/config/datakey_postprocess_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/config/datakey_postprocess_fn.md @@ -54,3 +54,6 @@ if (prevOrigValue) { } {:copy-code} ``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/alarm/cell_content_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/alarm/cell_content_fn.md new file mode 100644 index 0000000000..e757bed970 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/alarm/cell_content_fn.md @@ -0,0 +1,52 @@ +#### Cell content function + +
    +
    + +*function (value, alarm, ctx): string* + +A JavaScript function used to compute alarm cell content HTML depending on alarm field value. + +**Parameters:** + +
      +
    • value: any - An alarm field value displayed in the cell. +
    • +
    • alarm: AlarmDataInfo - An + AlarmDataInfo object + presenting basic alarm properties (ex. type, severity, originator, etc.) and
      provides access to other alarm or originator entity fields/attributes/timeseries declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return string value presenting cell content HTML. + +
    + +##### Examples + +* Format alarm start time using date/time pattern: + +```javascript +var startTime = value; +return startTime ? ctx.date.transform(startTime, 'yyyy-MM-dd HH:mm:ss') : ''; +{:copy-code} +``` + +* Styled cell content for originator alarm field: + +```javascript +var originator = value; +return '
    ' + originator + '
    '; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/alarm/cell_style_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/alarm/cell_style_fn.md new file mode 100644 index 0000000000..2c6ab6da20 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/alarm/cell_style_fn.md @@ -0,0 +1,62 @@ +#### Cell style function + +
    +
    + +*function (value, alarm, ctx): {[key: string]: string}* + +A JavaScript function used to compute alarm cell style depending on alarm field value. + +**Parameters:** + +
      +
    • value: any - An alarm field value displayed in the cell. +
    • +
    • alarm: AlarmDataInfo - An + AlarmDataInfo object + presenting basic alarm properties (ex. type, severity, originator, etc.) and
      provides access to other alarm or originator entity fields/attributes/timeseries declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return key/value object presenting style attributes. + +
    + +##### Examples + +* Set color depending on alarm severity: + +```javascript +var severity = value; +var color = 'black'; +switch (severity) { + case 'CRITICAL': + color = 'red'; + break; + case 'MAJOR': + color = 'orange'; + break; + case 'MINOR': + color = '#ffca3d'; + break; + case 'WARNING': + color = '#abab00'; + break; + case 'INDETERMINATE': + color = 'green'; + break; +} +return { + fontWeight: 'bold', + color: color +}; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/alarm/row_style_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/alarm/row_style_fn.md new file mode 100644 index 0000000000..e65a72fc0d --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/alarm/row_style_fn.md @@ -0,0 +1,59 @@ +#### Row style function + +
    +
    + +*function (alarm, ctx): {[key: string]: string}* + +A JavaScript function used to compute alarm row style depending on alarm value. + +**Parameters:** + +
      +
    • alarm: AlarmDataInfo - An + AlarmDataInfo object + presenting basic alarm properties (ex. type, severity, originator, etc.) and
      provides access to other alarm or originator entity fields/attributes/timeseries declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return key/value object presenting style attributes. + +
    + +##### Examples + +* Set row background color depending on alarm severity: + +```javascript +var severity = alarm.severity; +var color = '#fff'; +switch (severity) { + case 'CRITICAL': + color = 'red'; + break; + case 'MAJOR': + color = 'orange'; + break; + case 'MINOR': + color = '#ffca3d'; + break; + case 'WARNING': + color = '#abab00'; + break; + case 'INDETERMINATE': + color = 'green'; + break; +} +return { + backgroundColor: color +}; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_disabled_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_disabled_fn.md new file mode 100644 index 0000000000..b532cfa3f8 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_disabled_fn.md @@ -0,0 +1,40 @@ +#### Node disabled function + +
    +
    + +*function (nodeCtx): boolean* + +A JavaScript function evaluating whether current node should be disabled (not selectable). + +**Parameters:** + +
      +
    • nodeCtx: HierarchyNodeContext - An + HierarchyNodeContext object + containing entity field holding basic entity properties
      (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    + +**Returns:** + +`true` if node should be disabled (not selectable), `false` otherwise. + +
    + +##### Examples + +* Disable current node according to the value of example `nodeDisabled` attribute: + +```javascript +var data = nodeCtx.data; +if (data.hasOwnProperty('nodeDisabled') && data['nodeDisabled'] !== null) { + return data['nodeDisabled'] === 'true'; +} else { + return false; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_has_children_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_has_children_fn.md new file mode 100644 index 0000000000..1a71858c9b --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_has_children_fn.md @@ -0,0 +1,47 @@ +#### Node has children function + +
    +
    + +*function (nodeCtx): boolean* + +A JavaScript function evaluating whether current node has children (whether it can be expanded). + +**Parameters:** + +
      +
    • nodeCtx: HierarchyNodeContext - An + HierarchyNodeContext object + containing entity field holding basic entity properties
      (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    + +**Returns:** + +`true` if node should have children, `false` otherwise. + +
    + +##### Examples + +* Restrict entities hierarchy expansion up to third level: + +```javascript +return nodeCtx.level <= 2; +{:copy-code} +``` + +* Restrict entities expansion according to the value of example `nodeHasChildren` attribute: + +```javascript +var data = nodeCtx.data; +if (data.hasOwnProperty('nodeHasChildren') && data['nodeHasChildren'] !== null) { + return data['nodeHasChildren'] === 'true'; +} else { + return true; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_icon_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_icon_fn.md new file mode 100644 index 0000000000..1a3c0aec8e --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_icon_fn.md @@ -0,0 +1,53 @@ +#### Node icon function + +
    +
    + +*function (nodeCtx): {iconUrl?: string, materialIcon?: string} | 'default'* + +A JavaScript function used to compute node icon info. + +**Parameters:** + +
      +
    • nodeCtx: HierarchyNodeContext - An + HierarchyNodeContext object + containing entity field holding basic entity properties
      (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    + +**Returns:** + +Should return node icon info object with the following structure: + +```typescript +{ + iconUrl?: string, + materialIcon?: string +} +``` +Resulting object should contain either `materialIcon` or `iconUrl` property.
    +Where: + - `materialIcon` - name of the material icon to be used from the [Material Icons Library{:target="_blank"}](https://material.io/tools/icons); + - `iconUrl` - url of the external image to be used as node icon. + +Function can return `default` string value. In this case default icons according to entity type will be used. + +
    + +##### Examples + +* Use external image for devices which name starts with `Test` and use default icons for the rest of entities: + +```javascript +var entity = nodeCtx.entity; +if (entity.id.entityType === 'DEVICE' && entity.name.startsWith('Test')) { + return {iconUrl: 'https://avatars1.githubusercontent.com/u/14793288?v=4&s=117'}; +} else { + return 'default'; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_opened_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_opened_fn.md new file mode 100644 index 0000000000..e85a2b1aa9 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_opened_fn.md @@ -0,0 +1,35 @@ +#### Node opened by default function + +
    +
    + +*function (nodeCtx): boolean* + +A JavaScript function evaluating whether current node should be opened (expanded) when it first loaded. + +**Parameters:** + +
      +
    • nodeCtx: HierarchyNodeContext - An + HierarchyNodeContext object + containing entity field holding basic entity properties
      (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    + +**Returns:** + +`true` if node should be opened (expanded), `false` otherwise. + +
    + +##### Examples + +* Open by default nodes up to third level: + +```javascript +return nodeCtx.level <= 2; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_relation_query_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_relation_query_fn.md new file mode 100644 index 0000000000..f312483d07 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_relation_query_fn.md @@ -0,0 +1,49 @@ +#### Node relations query function + +
    +
    + +*function (nodeCtx): [EntityRelationsQuery{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/dda61383933cac9aa6821a77ff9b19291e69db9f/ui-ngx/src/app/shared/models/relation.models.ts#L69) | 'default'* + +A JavaScript function used to compute child nodes relations query for current node. + +**Parameters:** + +
      +
    • nodeCtx: HierarchyNodeContext - An + HierarchyNodeContext object + containing entity field holding basic entity properties
      (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    + +**Returns:** + +Should return [EntityRelationsQuery{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/dda61383933cac9aa6821a77ff9b19291e69db9f/ui-ngx/src/app/shared/models/relation.models.ts#L69) for current node used to fetch entity children.
    +Function can return `default` string value. In this case default relations query will be used. + +
    + +##### Examples + +* Fetch child entities having relations of type `Contains` from the current entity: + +```javascript +var entity = nodeCtx.entity; +var query = { + parameters: { + rootId: entity.id.id, + rootType: entity.id.entityType, + direction: "FROM", + maxLevel: 1 + }, + filters: [{ + relationType: "Contains", + entityTypes: [] + }] +}; +return query; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_text_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_text_fn.md new file mode 100644 index 0000000000..76b70a73fb --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_text_fn.md @@ -0,0 +1,41 @@ +#### Node text function + +
    +
    + +*function (nodeCtx): string* + +A JavaScript function used to compute text or HTML code for the current node. + +**Parameters:** + +
      +
    • nodeCtx: HierarchyNodeContext - An + HierarchyNodeContext object + containing entity field holding basic entity properties
      (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    + +**Returns:** + +Should return string value presenting text or HTML for the current node. + +
    + +##### Examples + +* Display entity name and optionally temperature value if it is present in entity attributes/timeseries: + +```javascript +var data = nodeCtx.data; +var entity = nodeCtx.entity; +var text = entity.name; +if (data.hasOwnProperty('temperature') && data['temperature'] !== null) { + text += " "+ data['temperature'] +" °C"; +} +return text; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/nodes_sort_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/nodes_sort_fn.md new file mode 100644 index 0000000000..779424b553 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/nodes_sort_fn.md @@ -0,0 +1,44 @@ +#### Nodes sort function + +
    +
    + +*function (nodeCtx1, nodeCtx2): number* + +A JavaScript function used to compare nodes of the same level when sorting. + +**Parameters:** + + + +**Returns:** + +Should return integer value presenting nodes comparison result: +- **less than 0** - sort `nodeCtx1` to an index lower than `nodeCtx2`; +- **0** - leave `nodeCtx1` and `nodeCtx2` unchanged with respect to each other; +- **greater than 0** - sort `nodeCtx2` to an index lower than `nodeCtx1`; + +
    + +##### Examples + +* Sort entities first by entity type in alphabetical order then by entity name in alphabetical order: + +```javascript +var result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType); +if (result === 0) { + result = nodeCtx1.entity.name.localeCompare(nodeCtx2.entity.name); +} +return result; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_content_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_content_fn.md new file mode 100644 index 0000000000..4458177327 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_content_fn.md @@ -0,0 +1,61 @@ +#### Cell content function + +
    +
    + +*function (value, entity, ctx): string* + +A JavaScript function used to compute entity cell content HTML depending on entity field value. + +**Parameters:** + +
      +
    • value: any - An entity field value displayed in the cell. +
    • +
    • entity: EntityData - An + EntityData object + presenting basic entity properties (ex. id, entityName) and
      provides access to other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return string value presenting cell content HTML. + +
    + +##### Examples + +* Format entity created time using date/time pattern: + +```javascript +var createdTime = value; +return createdTime ? ctx.date.transform(createdTime, 'yyyy-MM-dd HH:mm:ss') : ''; +{:copy-code} +``` + +* Styled cell content for device type field: + +```javascript +var deviceType = value; +var color = '#fff'; +switch (deviceType) { + case 'thermostat': + color = 'orange'; + break; + case 'default': + color = '#abab00'; + break; +} +return '
    ' + deviceType + '
    '; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_style_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_style_fn.md new file mode 100644 index 0000000000..692960cf4a --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_style_fn.md @@ -0,0 +1,52 @@ +#### Cell style function + +
    +
    + +*function (value, entity, ctx): {[key: string]: string}* + +A JavaScript function used to compute entity cell style depending on entity field value. + +**Parameters:** + +
      +
    • value: any - An entity field value displayed in the cell. +
    • +
    • entity: EntityData - An + EntityData object + presenting basic entity properties (ex. id, entityName) and
      provides access to other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return key/value object presenting style attributes. + +
    + +##### Examples + +* Set color depending on device temperature value: + +```javascript +var temperature = value; +var color = 'black'; +if (temperature) { + if (temperature > 25) { + color = 'red'; + } else { + color = 'green'; + } +} +return { + fontWeight: 'bold', + color: color +}; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entity/row_style_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entity/row_style_fn.md new file mode 100644 index 0000000000..f91befddce --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entity/row_style_fn.md @@ -0,0 +1,50 @@ +#### Row style function + +
    +
    + +*function (entity, ctx): {[key: string]: string}* + +A JavaScript function used to compute entity row style depending on entity value. + +**Parameters:** + +
      +
    • entity: EntityData - An + EntityData object + presenting basic entity properties (ex. id, entityName) and
      provides access to other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return key/value object presenting style attributes. + +
    + +##### Examples + +* Set row background color depending on device type: + +```javascript +var deviceType = entity.Type; +var color = '#fff'; +switch (deviceType) { + case 'thermostat': + color = 'orange'; + break; + case 'default': + color = '#abab00'; + break; +} +return { + backgroundColor: color +}; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/flot/point_shape_format_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/flot/point_shape_format_fn.md new file mode 100644 index 0000000000..c36f7e3cc7 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/flot/point_shape_format_fn.md @@ -0,0 +1,111 @@ +#### Point shape draw function + +
    +
    + +*function (ctx, x, y, radius, shadow): void* + +A JavaScript function used to draw custom shapes for chart points when `Custom function` for point shape is selected. + +**Parameters:** + +
      +
    • + ctx: CanvasRenderingContext2D - A canvas drawing context. +
    • +
    • + x number - point center X coordinate. +
    • +
    • + y number - point center Y coordinate. +
    • +
    • + radius number - point radius. +
    • +
    • + shadow boolean - whether to draw shadow. +
    • +
    + +
    + +##### Examples + +* Draw square: + +```javascript +var size = radius * Math.sqrt(Math.PI) / 2; +ctx.rect(x - size, y - size, size + size, size + size); +{:copy-code} +``` + +* Draw circle: + +```javascript +ctx.moveTo(x + radius, y); +ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); +{:copy-code} +``` + +* Draw diamond: + +```javascript +var size = radius * Math.sqrt(Math.PI / 2); +ctx.moveTo(x - size, y); +ctx.lineTo(x, y - size); +ctx.lineTo(x + size, y); +ctx.lineTo(x, y + size); +ctx.lineTo(x - size, y); +ctx.lineTo(x, y - size); +{:copy-code} +``` + +* Draw triangle: + +```javascript +var size = radius * Math.sqrt(2 * Math.PI / Math.sin(Math.PI / 3)); +var height = size * Math.sin(Math.PI / 3); +ctx.moveTo(x - size / 2, y + height / 2); +ctx.lineTo(x + size / 2, y + height / 2); +if (!shadow) { + ctx.lineTo(x, y - height / 2); + ctx.lineTo(x - size / 2, y + height / 2); + ctx.lineTo(x + size / 2, y + height / 2); +} +{:copy-code} +``` + +* Draw cross: + +```javascript +var size = radius * Math.sqrt(Math.PI) / 2; +ctx.moveTo(x - size, y - size); +ctx.lineTo(x + size, y + size); +ctx.moveTo(x - size, y + size); +ctx.lineTo(x + size, y - size); +{:copy-code} +``` + +* Draw ellipse: + +```javascript +if (!shadow) { + ctx.moveTo(x + radius, y); + ctx.arc(x, y, radius, 0, Math.PI * 2, false); +} +{:copy-code} +``` + +* Draw plus: + +```javascript +var size = radius * Math.sqrt(Math.PI / 2); +ctx.moveTo(x - size, y); +ctx.lineTo(x + size, y); +ctx.moveTo(x, y + size); +ctx.lineTo(x, y - size); +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/flot/ticks_formatter_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/flot/ticks_formatter_fn.md new file mode 100644 index 0000000000..673161c58d --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/flot/ticks_formatter_fn.md @@ -0,0 +1,93 @@ +#### Ticks formatter function + +
    +
    + +*function (value): string* + +A JavaScript function used to format Y axis ticks. + +**Parameters:** + +
      +
    • value: number - A tick value that should be formatted. +
    • +
    + +**Returns:** + +A string presenting the formatted value to be displayed as Y axis tick. + +
    + +##### Examples + +* Display ticks as is: + +```javascript +return value; +{:copy-code} +``` + +* Present ticks in Amperage (A) units and two decimal places: + +```javascript +return value.toFixed(2) + ' A'; +{:copy-code} +``` + +* Disable ticks: + +```javascript +return ''; +{:copy-code} +``` + +
      +
    • +To present axis ticks for true / false or 1 / 0 data.
      +Display On when value > 0 and <= 1,
      +Off when value = 0,
      +disable for all other values.
      +Note: To avoid duplicates among Y axis ticks it is recommended to set Steps size between ticks to 1: +
    • +
    + +```javascript +if (value > 0 && value <= 1) { + return 'On'; +} else if (value === 0) { + return 'Off'; +} else { + return ''; +} +{:copy-code} +``` + +
      +
    • +To present axis ticks for state or level data.
      +Display High when value >= 2,
      +Medium when value >= 1 and < 2,
      +Low when value >= 0 and < 1,
      +disable for all other values.
      +Note: To avoid duplicates among Y axis ticks it is recommended to set Steps size between ticks to 1
      +or other suitable value depending on your case: +
    • +
    + +```javascript +if (value >= 2) { + return 'High'; +} else if (value >= 1) { + return 'Medium'; +} else if (value >= 0) { + return 'Low'; +} else { + return ''; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/tooltip_value_format_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/flot/tooltip_value_format_fn.md similarity index 98% rename from ui-ngx/src/assets/help/en_US/widget/lib/tooltip_value_format_fn.md rename to ui-ngx/src/assets/help/en_US/widget/lib/flot/tooltip_value_format_fn.md index c3451cfe16..4ff02e3fab 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/tooltip_value_format_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/flot/tooltip_value_format_fn.md @@ -35,3 +35,6 @@ return value + ' °C'; return value.toFixed(2) + ' A'; {:copy-code} ``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/cell_content_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/cell_content_fn.md new file mode 100644 index 0000000000..0fe3b8b4e3 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/cell_content_fn.md @@ -0,0 +1,53 @@ +#### Cell content function + +
    +
    + +*function (value, rowData, ctx): string* + +A JavaScript function used to compute timeseries cell content HTML depending on timeseries field value. + +**Parameters:** + +
      +
    • value: any - An entity field value displayed in the cell. +
    • +
    • rowData: TimeseriesRow - A + TimeseriesRow object + presenting formattedTs (a string value of formatted timestamp) and
      timeseries values for each column declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return string value presenting cell content HTML. + +
    + +##### Examples + +* Styled cell content for temperature field: + +```javascript +var temperature = value; +var color = '#fff'; +if (temperature) { + if (temperature > 25) { + color = 'red'; + } else { + color = 'green'; + } +} +return '
    ' + temperature + '
    '; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/cell_style_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/cell_style_fn.md new file mode 100644 index 0000000000..202423fbb7 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/cell_style_fn.md @@ -0,0 +1,52 @@ +#### Cell style function + +
    +
    + +*function (value, rowData, ctx): {[key: string]: string}* + +A JavaScript function used to compute timeseries cell style depending on timeseries field value. + +**Parameters:** + +
      +
    • value: any - An timeseries field value displayed in the cell. +
    • +
    • rowData: TimeseriesRow - A + TimeseriesRow object + presenting formattedTs (a string value of formatted timestamp) and
      timeseries values for each column declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return key/value object presenting style attributes. + +
    + +##### Examples + +* Set color depending on temperature value: + +```javascript +var temperature = value; +var color = 'black'; +if (temperature) { + if (temperature > 25) { + color = 'red'; + } else { + color = 'green'; + } +} +return { + fontWeight: 'bold', + color: color +}; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/row_style_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/row_style_fn.md new file mode 100644 index 0000000000..fd1ea7ce7d --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/timeseries/row_style_fn.md @@ -0,0 +1,49 @@ +#### Row style function + +
    +
    + +*function (rowData, ctx): {[key: string]: string}* + +A JavaScript function used to compute timeseries row style depending on row value. + +**Parameters:** + +
      +
    • rowData: TimeseriesRow - A + TimeseriesRow object + presenting formattedTs (a string value of formatted timestamp) and
      timeseries values for each column declared in widget datasource configuration. +
    • +
    • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • +
    + +**Returns:** + +Should return key/value object presenting style attributes. + +
    + +##### Examples + +* Set row background color depending on temperature value: + +```javascript +var temperature = rowData.temperature; +var color = '#fff'; +if (temperature) { + if (temperature > 25) { + color = 'red'; + } else { + color = 'green'; + } +} +return { + backgroundColor: color +}; +{:copy-code} +``` + +
    +
    From 0b3a287530e8f4d7b41c82fe1c081a7aa2f71b16 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 20 Oct 2021 10:24:11 +0300 Subject: [PATCH 093/303] Fixed double requests on aliases entity autocomplete --- .../alias/aliases-entity-autocomplete.component.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alias/aliases-entity-autocomplete.component.ts b/ui-ngx/src/app/modules/home/components/alias/aliases-entity-autocomplete.component.ts index a56c19c281..9fbfd4c261 100644 --- a/ui-ngx/src/app/modules/home/components/alias/aliases-entity-autocomplete.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/aliases-entity-autocomplete.component.ts @@ -17,7 +17,7 @@ import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Observable, of } from 'rxjs'; -import { catchError, debounceTime, distinctUntilChanged, map, startWith, switchMap, tap } from 'rxjs/operators'; +import { catchError, debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators'; import { emptyPageData, PageData } from '@shared/models/page/page-data'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -26,6 +26,7 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { EntityInfo } from '@shared/models/entity.models'; import { EntityFilter } from '@shared/models/query/query.models'; import { EntityService } from '@core/http/entity.service'; +import { isDefinedAndNotNull } from '@core/utils'; @Component({ selector: 'tb-aliases-entity-autocomplete', @@ -98,10 +99,10 @@ export class AliasesEntityAutocompleteComponent implements ControlValueAccessor, } this.updateView(modelValue); }), - startWith(''), map(value => value ? (typeof value === 'string' ? value : value.name) : ''), distinctUntilChanged(), - switchMap(name => this.fetchEntityInfos(name)) + switchMap(name => this.fetchEntityInfos(name)), + share() ); } @@ -114,12 +115,12 @@ export class AliasesEntityAutocompleteComponent implements ControlValueAccessor, writeValue(value: EntityInfo | null): void { this.searchText = ''; - if (value != null) { + if (isDefinedAndNotNull(value)) { this.modelValue = value; this.selectEntityInfoFormGroup.get('entityInfo').patchValue(value, {emitEvent: true}); } else { this.modelValue = null; - this.selectEntityInfoFormGroup.get('entityInfo').patchValue(null, {emitEvent: true}); + this.selectEntityInfoFormGroup.get('entityInfo').patchValue(null, {emitEvent: false}); } } From 3c665ecd498ce25df219e81072fa84bee7244a30 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Wed, 20 Oct 2021 11:35:08 +0300 Subject: [PATCH 094/303] device profile data model updates --- .../common/data/device/data/DeviceConfiguration.java | 4 ++-- .../data/device/data/DeviceTransportConfiguration.java | 5 ++--- .../common/data/device/profile/AlarmConditionSpec.java | 6 ++---- .../server/common/data/device/profile/AlarmSchedule.java | 4 ---- .../common/data/device/profile/DeviceProfileAlarm.java | 4 ++-- .../data/device/profile/DeviceProfileConfiguration.java | 8 +++----- .../common/data/device/profile/DeviceProfileData.java | 4 ++-- .../profile/DeviceProfileProvisionConfiguration.java | 6 +----- .../server/common/data/query/KeyFilterPredicate.java | 6 ++---- 9 files changed, 16 insertions(+), 31 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java index 46d7a3d615..16f751a136 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java @@ -15,11 +15,11 @@ */ package org.thingsboard.server.common.data.device.data; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.DeviceProfileType; @ApiModel @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.DeviceProfileType; @JsonSubTypes.Type(value = DefaultDeviceConfiguration.class, name = "DEFAULT")}) public interface DeviceConfiguration { - @ApiModelProperty(position = 1, value = "Device profile type", allowableValues = "DEFAULT") + @JsonIgnore DeviceProfileType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceTransportConfiguration.java index bfa7fc672c..e39ed8ac15 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceTransportConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceTransportConfiguration.java @@ -15,11 +15,11 @@ */ package org.thingsboard.server.common.data.device.data; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.DeviceTransportType; import java.io.Serializable; @@ -37,8 +37,7 @@ import java.io.Serializable; @JsonSubTypes.Type(value = Lwm2mDeviceTransportConfiguration.class, name = "LWM2M"), @JsonSubTypes.Type(value = SnmpDeviceTransportConfiguration.class, name = "SNMP")}) public interface DeviceTransportConfiguration extends Serializable { - - @ApiModelProperty(position = 1, value = "Device transport type", example = "MQTT") + @JsonIgnore DeviceTransportType getType(); default void validate() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java index d1346d9778..1a34894997 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java @@ -15,15 +15,13 @@ */ package org.thingsboard.server.common.data.device.profile; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; -@ApiModel @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -35,7 +33,7 @@ import java.io.Serializable; @JsonSubTypes.Type(value = RepeatingAlarmConditionSpec.class, name = "REPEATING")}) public interface AlarmConditionSpec extends Serializable { - @ApiModelProperty(position = 1, value = "String value representing alarm condition type. See method implementation notes for more examples") + @JsonIgnore AlarmConditionSpecType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java index bf898603a3..1d5eceb1aa 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java @@ -18,12 +18,9 @@ package org.thingsboard.server.common.data.device.profile; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; -@ApiModel @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -35,7 +32,6 @@ import java.io.Serializable; @JsonSubTypes.Type(value = CustomTimeSchedule.class, name = "CUSTOM")}) public interface AlarmSchedule extends Serializable { - @ApiModelProperty(position = 1, value = "Alarm schedule type. See method implementation notes for more examples", example = "ANY_TIME") AlarmScheduleType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java index abbb7858ff..806925f244 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java @@ -21,8 +21,8 @@ import lombok.Data; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.validation.NoXss; -import java.io.Serializable; import javax.validation.Valid; +import java.io.Serializable; import java.util.List; import java.util.TreeMap; @@ -33,7 +33,7 @@ public class DeviceProfileAlarm implements Serializable { @ApiModelProperty(position = 1, value = "String value representing the alarm rule id", example = "highTemperatureAlarmID") private String id; @NoXss - @ApiModelProperty(position = 2, value = "String value representing type of the Alarm", example = "High Temperature Alarm") + @ApiModelProperty(position = 2, value = "String value representing type of the alarm", example = "High Temperature Alarm") private String alarmType; @Valid diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java index f1792225fb..2d0a5fcf10 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java @@ -15,26 +15,24 @@ */ package org.thingsboard.server.common.data.device.profile; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.DeviceProfileType; import java.io.Serializable; -@ApiModel @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ - @JsonSubTypes.Type(value = DefaultDeviceProfileConfiguration.class, name = "DEFAULT")}) + @JsonSubTypes.Type(value = DefaultDeviceProfileConfiguration.class, name = "DEFAULT")}) public interface DeviceProfileConfiguration extends Serializable { - @ApiModelProperty(position = 1, value = "Device profile type", allowableValues = "DEFAULT") + @JsonIgnore DeviceProfileType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java index adeb77d315..d56edcd323 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java @@ -19,15 +19,15 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import java.io.Serializable; import javax.validation.Valid; +import java.io.Serializable; import java.util.List; @ApiModel @Data public class DeviceProfileData implements Serializable { - @ApiModelProperty(position = 1, value = "JSON object of device profile configuration for device profile type") + @ApiModelProperty(position = 1, value = "JSON object of device profile configuration") private DeviceProfileConfiguration configuration; @Valid @ApiModelProperty(position = 2, value = "JSON object of device profile transport configuration") diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileProvisionConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileProvisionConfiguration.java index 869a6ce0f8..f4582786d1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileProvisionConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileProvisionConfiguration.java @@ -19,13 +19,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import java.io.Serializable; -@ApiModel @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -37,10 +34,9 @@ import java.io.Serializable; @JsonSubTypes.Type(value = CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration.class, name = "CHECK_PRE_PROVISIONED_DEVICES")}) public interface DeviceProfileProvisionConfiguration extends Serializable { - @ApiModelProperty(position = 1, value = "String value representing the secret key used to verify provisioning of the device defined in the device profile", example = "bjrj9172va82hvwqtp5b") String getProvisionDeviceSecret(); - @ApiModelProperty(position = 2, value = "Device provisioning strategy for device profile", example = "ALLOW_CREATE_NEW_DEVICES") + @JsonIgnore DeviceProfileProvisionType getType(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilterPredicate.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilterPredicate.java index 7d12c4d460..79f2f0e132 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilterPredicate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/KeyFilterPredicate.java @@ -15,14 +15,12 @@ */ package org.thingsboard.server.common.data.query; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; -@ApiModel @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, @@ -34,7 +32,7 @@ import java.io.Serializable; @JsonSubTypes.Type(value = ComplexFilterPredicate.class, name = "COMPLEX")}) public interface KeyFilterPredicate extends Serializable { - @ApiModelProperty(position = 1, value = "String value representing filter predicate type. See method implementation notes for more examples", example = "BOOLEAN") + @JsonIgnore FilterPredicateType getType(); } From 91d614bab3a8529128d9ac9fd9cd1795a5a07fa3 Mon Sep 17 00:00:00 2001 From: Mariia Synelnyk <44849051+Mariesnlk@users.noreply.github.com> Date: Wed, 20 Oct 2021 12:05:40 +0300 Subject: [PATCH 095/303] [3.2.2] Feature/swagger telemetry controller (#5374) * add more notes to TelemetryController * add detailed notes to Telemetryontroller and try to fix Inline Model * remove responsecontainer from @ApiOperaion * description updated for Telemetry Controller API calls Co-authored-by: ShvaykaD --- .../controller/TelemetryController.java | 196 +++++++++++++++--- .../service/telemetry/AttributeData.java | 7 + .../server/service/telemetry/TsData.java | 6 + 3 files changed, 176 insertions(+), 33 deletions(-) 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 b39492539b..1c480537c2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -28,10 +28,13 @@ import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.StringUtils; @@ -113,12 +116,43 @@ public class TelemetryController extends BaseController { private static final String ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. For example, 'active,inactivityAlarmTime'."; private static final String ATTRIBUTES_SCOPE_ALLOWED_VALUES = "SERVER_SCOPE, CLIENT_SCOPE, SHARED_SCOPE"; private static final String ATTRIBUTES_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}'"; - - private static final String TELEMETRY_KEYS_DESCRIPTION = "A string value representing the comma-separated list of timeseries keys. If keys are not selected, the result will return all latest timeseries. For example, 'temp,humidity'."; - private static final String TELEMETRY_SCOPE_DESCRIPTION = "Value is not used in the API call implementation"; - private static final String TELEMETRY_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}' or '{\"ts\":1527863043000,\"values\":{\"key1\":\"value1\",\"key2\":\"value2\"}}'"; - - private static final String STRICT_DATA_TYPES_DESCRIPTION = "A boolean value to specify if values of selected timeseries keys will representing a string (by default) or use strict data type."; + private static final String ATTRIBUTE_DATA_CLASS_DESCRIPTION = "AttributeData class represents information regarding a particular attribute and includes the next parameters: 'lastUpdatesTs' - a long value representing the timestamp of the last attribute modification in milliseconds. 'key' - attribute key name, and 'value' - attribute value."; + private static final String GET_ALL_ATTRIBUTES_BASE_DESCRIPTION = "Returns a JSON structure that represents a list of AttributeData class objects for the selected entity based on the specified comma-separated list of attribute key names. " + ATTRIBUTE_DATA_CLASS_DESCRIPTION; + private static final String GET_ALL_ATTRIBUTES_BY_SCOPE_BASE_DESCRIPTION = "Returns a JSON structure that represents a list of AttributeData class objects for the selected entity based on the attributes scope selected and a comma-separated list of attribute key names. " + ATTRIBUTE_DATA_CLASS_DESCRIPTION; + + private static final String TS_DATA_CLASS_DESCRIPTION = "TsData class is a timeseries data point for specific telemetry key that includes 'value' - object value, and 'ts' - a long value representing timestamp in milliseconds for this value. "; + + private static final String TELEMETRY_KEYS_BASE_DESCRIPTION = "A string value representing the comma-separated list of telemetry keys."; + private static final String TELEMETRY_KEYS_DESCRIPTION = TELEMETRY_KEYS_BASE_DESCRIPTION + " If keys are not selected, the result will return all latest timeseries. For example, 'temp,humidity'."; + private static final String TELEMETRY_SCOPE_DESCRIPTION = "Value is not used in the API call implementation. However, you need to specify whatever value cause scope is a path variable."; + private static final String TELEMETRY_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}' or '{\"ts\":1527863043000,\"values\":{\"key1\":\"value1\",\"key2\":\"value2\"}}' or [{\"ts\":1527863043000,\"values\":{\"key1\":\"value1\",\"key2\":\"value2\"}}, {\"ts\":1527863053000,\"values\":{\"key1\":\"value3\",\"key2\":\"value4\"}}]"; + + + private static final String STRICT_DATA_TYPES_DESCRIPTION = "A boolean value to specify if values of selected telemetry keys will represent string values(by default) or use strict data type."; + private static final String INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION = "Referencing a non-existing entity Id or invalid entity type will cause an error. "; + + private static final String SAVE_ENTITY_ATTRIBUTES_DESCRIPTION = "Creates or updates the entity attributes based on entity id, entity type, specified attributes scope " + + "and request payload that represents a JSON object with key-value format of attributes to create or update. " + + "For example, '{\"temperature\": 26}'. Key is a unique parameter and cannot be overwritten. Only value can be overwritten for the key. "; + private static final String SAVE_ATTIRIBUTES_STATUS_OK = "Attribute from the request was created or updated. "; + private static final String INVALID_STRUCTURE_OF_THE_REQUEST = "Invalid structure of the request"; + private static final String SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST = INVALID_STRUCTURE_OF_THE_REQUEST + " or invalid attributes scope provided."; + private static final String SAVE_ENTITY_ATTRIBUTES_STATUS_OK = "Platform creates an audit log event about entity attributes updates with action type 'ATTRIBUTES_UPDATED', " + + "and also sends event msg to the rule engine with msg type 'ATTRIBUTES_UPDATED'."; + private static final String SAVE_ENTITY_ATTRIBUTES_STATUS_UNAUTHORIZED = "User is not authorized to save entity attributes for selected entity. Most likely, User belongs to different Customer or Tenant."; + private static final String SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR = "The exception was thrown during processing the request. " + + "Platform creates an audit log event about entity attributes updates with action type 'ATTRIBUTES_UPDATED' that includes an error stacktrace."; + private static final String SAVE_ENTITY_TIMESERIES_DESCRIPTION = "Creates or updates the entity timeseries based on entity id, entity type " + + "and request payload that represents a JSON object with key-value or ts-values format. " + + "For example, '{\"temperature\": 26}' or '{\"ts\":1634712287000,\"values\":{\"temperature\":26, \"humidity\":87}}', " + + "or JSON array with inner objects inside of ts-values format. " + + "For example, '[{\"ts\":1634712287000,\"values\":{\"temperature\":26, \"humidity\":87}}, {\"ts\":1634712588000,\"values\":{\"temperature\":25, \"humidity\":88}}]'. " + + "The scope parameter is not used in the API call implementation but should be specified whatever value because it is used as a path variable. "; + private static final String SAVE_ENTITY_TIMESERIES_STATUS_OK = "Timeseries from the request was created or updated. " + + "Platform creates an audit log event about entity timeseries updates with action type 'TIMESERIES_UPDATED'."; + private static final String SAVE_ENTITY_TIMESERIES_STATUS_UNAUTHORIZED = "User is not authorized to save entity timeseries for selected entity. Most likely, User belongs to different Customer or Tenant."; + private static final String SAVE_ENTITY_TIMESERIES_STATUS_INTERNAL_SERVER_ERROR = "The exception was thrown during processing the request. " + + "Platform creates an audit log event about entity timeseries updates with action type 'TIMESERIES_UPDATED' that includes an error stacktrace."; @Autowired private TimeseriesService tsService; @@ -146,7 +180,10 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Get all attribute keys (getAttributeKeys)", - notes = "Returns key names for the selected entity.") + notes = "Returns a list of all attribute key names for the selected entity. " + + "In the case of device entity specified, a response will include merged attribute key names list from each scope: " + + "SERVER_SCOPE, CLIENT_SCOPE, SHARED_SCOPE. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes", method = RequestMethod.GET) @ResponseBody @@ -156,8 +193,10 @@ public class TelemetryController extends BaseController { return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); } - @ApiOperation(value = "Get all attributes by scope (getAttributeKeysByScope)", - notes = "Returns key names of specified scope for the selected entity.") + @ApiOperation(value = "Get all attributes keys by scope (getAttributeKeysByScope)", + notes = "Returns a list of attribute key names from the specified attributes scope for the selected entity. " + + "If scope parameter is omitted, Get all attribute keys(getAttributeKeys) API will be called. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}", method = RequestMethod.GET) @ResponseBody @@ -170,7 +209,9 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Get attributes (getAttributes)", - notes = "Returns JSON array of AttributeData objects for the selected entity.") + notes = GET_ALL_ATTRIBUTES_BASE_DESCRIPTION + " If 'keys' parameter is omitted, AttributeData class objects will be added to the response for all existing keys of the selected entity. " + + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes", method = RequestMethod.GET) @ResponseBody @@ -184,7 +225,11 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Get attributes by scope (getAttributesByScope)", - notes = "Returns JSON array of AttributeData objects for the selected entity.") + notes = GET_ALL_ATTRIBUTES_BY_SCOPE_BASE_DESCRIPTION + " In case that 'keys' parameter is not selected, " + + "AttributeData class objects will be added to the response for all existing attribute keys from the " + + "specified attributes scope of the selected entity. If 'scope' parameter is omitted, " + + "Get attributes (getAttributes) API will be called. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes/{scope}", method = RequestMethod.GET) @ResponseBody @@ -199,7 +244,9 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Get timeseries keys (getTimeseriesKeys)", - notes = "Returns latest timeseries keys for selected entity.") + notes = "Returns a list of all telemetry key names for the selected entity based on entity id and entity type specified. " + + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/timeseries", method = RequestMethod.GET) @ResponseBody @@ -211,7 +258,9 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Get latest timeseries (getLatestTimeseries)", - notes = "Returns JSON object with mapping latest timeseries keys to JSON arrays of TsData objects for the selected entity.") + notes = "Returns a JSON structure that represents a Map, where the map key is a telemetry key name " + + "and map value - is a singleton list of TsData class objects. " + TS_DATA_CLASS_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET) @ResponseBody @@ -222,30 +271,35 @@ public class TelemetryController extends BaseController { @ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION) @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { SecurityUser user = getCurrentUser(); - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); } @ApiOperation(value = "Get timeseries (getTimeseries)", - notes = "Returns JSON object with mapping timeseries keys to JSON arrays of TsData objects based on specified filters for the selected entity.") + notes = "Returns a JSON structure that represents a Map, where the map key is a telemetry key name " + + "and map value - is a list of TsData class objects. " + TS_DATA_CLASS_DESCRIPTION + + "This method allows us to group original data into intervals and aggregate it using one of the aggregation methods or just limit the number of TsData objects to fetch for each key specified. " + + "See the desription of the request parameters for more details. " + + "The result can also be sorted in ascending or descending order. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"}) @ResponseBody public DeferredResult getTimeseries( @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @PathVariable("entityId") String entityIdStr, - @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keys, - @ApiParam(value = "A long value representing the start timestamp(milliseconds) of search time range.") + @ApiParam(value = TELEMETRY_KEYS_BASE_DESCRIPTION) @RequestParam(name = "keys") String keys, + @ApiParam(value = "A long value representing the start timestamp of search time range in milliseconds.") @RequestParam(name = "startTs") Long startTs, - @ApiParam(value = "A long value representing the end timestamp(milliseconds) of search time range.") + @ApiParam(value = "A long value representing the end timestamp of search time range in milliseconds.") @RequestParam(name = "endTs") Long endTs, - @ApiParam(value = "A long value representing the aggregation interval(milliseconds) range.") + @ApiParam(value = "A long value representing the aggregation interval range in milliseconds.") @RequestParam(name = "interval", defaultValue = "0") Long interval, - @ApiParam(value = "An integer value representing max number of selected data points.", defaultValue = "100") + @ApiParam(value = "An integer value that represents a max number of timeseries data points to fetch." + + " This parameter is used only in the case if 'agg' parameter is set to 'NONE'.", defaultValue = "100") @RequestParam(name = "limit", defaultValue = "100") Integer limit, @ApiParam(value = "A string value representing the aggregation function. " + - "If the interval is not specified, 'agg' parameter will be converted to 'NONE' value.", + "If the interval is not specified, 'agg' parameter will use 'NONE' value.", allowableValues = "MIN, MAX, AVG, SUM, COUNT, NONE") @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @@ -263,7 +317,21 @@ public class TelemetryController extends BaseController { }); } - @ApiOperation(value = "Save or update device attributes (saveDeviceAttributes)") + @ApiOperation(value = "Save or update device attributes (saveDeviceAttributes)", + notes = "Creates or updates the device attributes based on device id, specified attribute scope, " + + "and request payload that represents a JSON object with key-value format of attributes to create or update. " + + "For example, '{\"temperature\": 26}'. Key is a unique parameter and cannot be overwritten. Only value can " + + "be overwritten for the key. ", + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponses(value = { + @ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK + + "Platform creates an audit log event about device attributes updates with action type 'ATTRIBUTES_UPDATED', " + + "and also sends event msg to the rule engine with msg type 'ATTRIBUTES_UPDATED'."), + @ApiResponse(code = 400, message = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST), + @ApiResponse(code = 401, message = "User is not authorized to save device attributes for selected device. Most likely, User belongs to different Customer or Tenant."), + @ApiResponse(code = 500, message = "The exception was thrown during processing the request. " + + "Platform creates an audit log event about device attributes updates with action type 'ATTRIBUTES_UPDATED' that includes an error stacktrace."), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.POST) @ResponseBody @@ -275,7 +343,15 @@ public class TelemetryController extends BaseController { return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Save or update attributes (saveEntityAttributesV1)") + @ApiOperation(value = "Save or update attributes (saveEntityAttributesV1)", + notes = SAVE_ENTITY_ATTRIBUTES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponses(value = { + @ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK), + @ApiResponse(code = 400, message = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST), + @ApiResponse(code = 401, message = SAVE_ENTITY_ATTRIBUTES_STATUS_UNAUTHORIZED), + @ApiResponse(code = 500, message = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.POST) @ResponseBody @@ -288,7 +364,15 @@ public class TelemetryController extends BaseController { return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Save or update attributes (saveEntityAttributesV2)") + @ApiOperation(value = "Save or update attributes (saveEntityAttributesV2)", + notes = SAVE_ENTITY_ATTRIBUTES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponses(value = { + @ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK), + @ApiResponse(code = 400, message = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST), + @ApiResponse(code = 401, message = SAVE_ENTITY_ATTRIBUTES_STATUS_UNAUTHORIZED), + @ApiResponse(code = 500, message = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/attributes/{scope}", method = RequestMethod.POST) @ResponseBody @@ -301,7 +385,15 @@ public class TelemetryController extends BaseController { return saveAttributes(getTenantId(), entityId, scope, request); } - @ApiOperation(value = "Save or update telemetry (saveEntityTelemetry)") + @ApiOperation(value = "Save or update telemetry (saveEntityTelemetry)", + notes = SAVE_ENTITY_TIMESERIES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponses(value = { + @ApiResponse(code = 200, message = SAVE_ENTITY_TIMESERIES_STATUS_OK), + @ApiResponse(code = 400, message = INVALID_STRUCTURE_OF_THE_REQUEST), + @ApiResponse(code = 401, message = SAVE_ENTITY_TIMESERIES_STATUS_UNAUTHORIZED), + @ApiResponse(code = 500, message = SAVE_ENTITY_TIMESERIES_STATUS_INTERNAL_SERVER_ERROR), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}", method = RequestMethod.POST) @ResponseBody @@ -315,7 +407,14 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Save or update telemetry with TTL (saveEntityTelemetryWithTTL)", - notes = "The TTL parameter is used to extract the number of days to store the data.") + notes = SAVE_ENTITY_TIMESERIES_DESCRIPTION + "The ttl parameter used only in case of Cassandra DB use for timeseries data storage. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponses(value = { + @ApiResponse(code = 200, message = SAVE_ENTITY_TIMESERIES_STATUS_OK), + @ApiResponse(code = 400, message = INVALID_STRUCTURE_OF_THE_REQUEST), + @ApiResponse(code = 401, message = SAVE_ENTITY_TIMESERIES_STATUS_UNAUTHORIZED), + @ApiResponse(code = 500, message = SAVE_ENTITY_TIMESERIES_STATUS_INTERNAL_SERVER_ERROR), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}/{ttl}", method = RequestMethod.POST) @ResponseBody @@ -323,14 +422,25 @@ public class TelemetryController extends BaseController { @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION) @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION) @PathVariable("entityId") String entityIdStr, @ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION) @PathVariable("scope") String scope, - @ApiParam(value = "A long value representing TTL(Time to Live) parameter.") @PathVariable("ttl") Long ttl, + @ApiParam(value = "A long value representing TTL (Time to Live) parameter.") @PathVariable("ttl") Long ttl, @ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, ttl); } @ApiOperation(value = "Delete entity timeseries (deleteEntityTimeseries)", - notes = "Delete timeseries in the specified time range for selected entity.") + notes = "Delete timeseries for selected entity based on entity id, entity type, keys " + + "and removal time range. To delete all data for keys parameter 'deleteAllDataForKeys' should be set to true, " + + "otherwise, will be deleted data that is in range of the selected time interval. ", + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Timeseries for the selected keys in the request was removed. " + + "Platform creates an audit log event about entity timeseries removal with action type 'TIMESERIES_DELETED'."), + @ApiResponse(code = 400, message = "Platform returns a bad request in case if keys list is empty or start and end timestamp values is empty when deleteAllDataForKeys is set to false."), + @ApiResponse(code = 401, message = "User is not authorized to delete entity timeseries for selected entity. Most likely, User belongs to different Customer or Tenant."), + @ApiResponse(code = 500, message = "The exception was thrown during processing the request. " + + "Platform creates an audit log event about entity timeseries removal with action type 'TIMESERIES_DELETED' that includes an error stacktrace."), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/timeseries/delete", method = RequestMethod.DELETE) @ResponseBody @@ -340,11 +450,11 @@ public class TelemetryController extends BaseController { @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys") String keysStr, @ApiParam(value = "A boolean value to specify if should be deleted all data for selected keys or only data that are in the selected time range.") @RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys, - @ApiParam(value = "A long value representing the start timestamp(milliseconds) of removal time range.") + @ApiParam(value = "A long value representing the start timestamp of removal time range in milliseconds.") @RequestParam(name = "startTs", required = false) Long startTs, - @ApiParam(value = "A long value representing the end timestamp(milliseconds) of removal time range.") + @ApiParam(value = "A long value representing the end timestamp of removal time range in milliseconds.") @RequestParam(name = "endTs", required = false) Long endTs, - @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten if the current latest value was removed, otherwise, the new latest value will not set.") + @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.") @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); @@ -395,7 +505,17 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Delete device attributes (deleteEntityAttributes)", - notes = "Delete attributes of specified scope for selected device.") + notes = "Delete device attributes from the specified attributes scope based on device id and a list of keys to delete. " + + "Selected keys will be deleted only if there are exist in the specified attribute scope. Referencing a non-existing device Id will cause an error", + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Device attributes was removed for the selected keys in the request. " + + "Platform creates an audit log event about device attributes removal with action type 'ATTRIBUTES_DELETED'."), + @ApiResponse(code = 400, message = "Platform returns a bad request in case if keys or scope are not specified."), + @ApiResponse(code = 401, message = "User is not authorized to delete device attributes for selected entity. Most likely, User belongs to different Customer or Tenant."), + @ApiResponse(code = 500, message = "The exception was thrown during processing the request. " + + "Platform creates an audit log event about device attributes removal with action type 'ATTRIBUTES_DELETED' that includes an error stacktrace."), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.DELETE) @ResponseBody @@ -408,7 +528,17 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Delete entity attributes (deleteEntityAttributes)", - notes = "Delete attributes of specified scope for selected entity.") + notes = "Delete entity attributes from the specified attributes scope based on entity id, entity type and a list of keys to delete. " + + "Selected keys will be deleted only if there are exist in the specified attribute scope." + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Entity attributes was removed for the selected keys in the request. " + + "Platform creates an audit log event about entity attributes removal with action type 'ATTRIBUTES_DELETED'."), + @ApiResponse(code = 400, message = "Platform returns a bad request in case if keys or scope are not specified."), + @ApiResponse(code = 401, message = "User is not authorized to delete entity attributes for selected entity. Most likely, User belongs to different Customer or Tenant."), + @ApiResponse(code = 500, message = "The exception was thrown during processing the request. " + + "Platform creates an audit log event about entity attributes removal with action type 'ATTRIBUTES_DELETED' that includes an error stacktrace."), + }) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.DELETE) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java b/application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java index 0ee615d048..56ce42e1c6 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java @@ -15,6 +15,10 @@ */ package org.thingsboard.server.service.telemetry; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel public class AttributeData implements Comparable{ private final long lastUpdateTs; @@ -28,14 +32,17 @@ public class AttributeData implements Comparable{ this.value = value; } + @ApiModelProperty(position = 1, value = "Timestamp last updated attribute, in milliseconds", example = "1609459200000", readOnly = true) public long getLastUpdateTs() { return lastUpdateTs; } + @ApiModelProperty(position = 2, value = "String representing attribute key", example = "active", readOnly = true) public String getKey() { return key; } + @ApiModelProperty(position = 3, value = "Object representing value of attribute key", example = "false", readOnly = true) public Object getValue() { return value; } diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java b/application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java index 3f8a1fffca..3b23d7cff1 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java @@ -15,6 +15,10 @@ */ package org.thingsboard.server.service.telemetry; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel public class TsData implements Comparable{ private final long ts; @@ -26,10 +30,12 @@ public class TsData implements Comparable{ this.value = value; } + @ApiModelProperty(position = 1, value = "Timestamp last updated timeseries, in milliseconds", example = "1609459200000", readOnly = true) public long getTs() { return ts; } + @ApiModelProperty(position = 2, value = "Object representing value of timeseries key", example = "20", readOnly = true) public Object getValue() { return value; } From 3e798d13aa45a6fd65786bd6c7e20507f1754409 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 20 Oct 2021 12:14:55 +0300 Subject: [PATCH 096/303] Improve qrcode widget. Add helps for qrcode and markdown widgets --- .../json/system/widget_bundles/cards.json | 10 ++-- .../widget/lib/markdown-widget.component.ts | 15 ++--- .../widget/lib/qrcode-widget.component.html | 6 +- .../widget/lib/qrcode-widget.component.ts | 22 +++---- .../widget/lib/markdown/markdown_text_fn.md | 58 +++++++++++++++++++ .../en_US/widget/lib/qrcode/qrcode_text_fn.md | 55 ++++++++++++++++++ 6 files changed, 135 insertions(+), 31 deletions(-) create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/qrcode/qrcode_text_fn.md diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 384fadd463..4fb124fc06 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -162,10 +162,10 @@ "resources": [], "templateHtml": "\n", "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.qrCodeWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n dataKeysOptional: true,\n singleEntity: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"QR Code\",\n \"properties\": {\n \"qrCodeTextPattern\": {\n \"title\": \"QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useQrCodeTextFunction\": {\n \"title\": \"Use QR code text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"qrCodeTextFunction\": {\n \"title\": \"QR code text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return data['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"qrCodeTextPattern\",\n \"useQrCodeTextFunction\",\n {\n \"key\": \"qrCodeTextFunction\",\n \"type\": \"javascript\"\n }\n ]\n}\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.qrCodeWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"QR Code\",\n \"properties\": {\n \"qrCodeTextPattern\": {\n \"title\": \"QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useQrCodeTextFunction\": {\n \"title\": \"Use QR code text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"qrCodeTextFunction\": {\n \"title\": \"QR code text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"qrCodeTextPattern\",\n \"condition\": \"model.useQrCodeTextFunction !== true\"\n },\n \"useQrCodeTextFunction\",\n {\n \"key\": \"qrCodeTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/qrcode/qrcode_text_fn\",\n \"condition\": \"model.useQrCodeTextFunction === true\"\n }\n ]\n}\n", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7036904308224163,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"qrCodeTextPattern\":\"${entityName}\",\"useQrCodeTextFunction\":false,\"qrCodeTextFunction\":\"return data['entityName'];\"},\"title\":\"QR Code\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7036904308224163,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"qrCodeTextPattern\":\"${entityName}\",\"useQrCodeTextFunction\":false,\"qrCodeTextFunction\":\"return data[0] ? data[0]['entityName'] : '';\"},\"title\":\"QR Code\"}" } }, { @@ -181,9 +181,9 @@ "templateHtml": "\n", "templateCss": "#container tb-markdown-widget {\n height: 100%;\n display: block;\n}\n\n#container tb-markdown-widget .tb-markdown-view {\n height: 100%;\n overflow: auto;\n}\n", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.markdownWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n },\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\"\n }\n ]\n}\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\",\n \"condition\": \"model.useMarkdownTextFunction !== true\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n },\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/markdown/markdown_text_fn\",\n \"condition\": \"model.useMarkdownTextFunction === true\"\n }\n ]\n}\n", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown/HTML card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"},\"title\":\"Markdown/HTML Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown/HTML card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\",\"useMarkdownTextFunction\":false},\"title\":\"Markdown/HTML Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" } } ] diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts index e96f775007..fd0197996e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts @@ -99,15 +99,12 @@ export class MarkdownWidgetComponent extends PageComponent implements OnInit { } else { initialData = []; } - let markdownText: string; - if (initialData) { - const data = parseData(initialData); - markdownText = this.settings.useMarkdownTextFunction ? - safeExecute(this.markdownTextFunction, [data]) : this.settings.markdownTextPattern; - const allData = flatData(data); - const replaceInfo = processPattern(markdownText, allData); - markdownText = fillPattern(markdownText, replaceInfo, allData); - } + const data = parseData(initialData); + let markdownText = this.settings.useMarkdownTextFunction ? + safeExecute(this.markdownTextFunction, [data]) : this.settings.markdownTextPattern; + const allData = flatData(data); + const replaceInfo = processPattern(markdownText, allData); + markdownText = fillPattern(markdownText, replaceInfo, allData); if (this.markdownText !== markdownText) { this.markdownText = this.utils.customTranslation(markdownText, markdownText); this.cd.detectChanges(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.html index 48f888340a..74590433f4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.html @@ -17,8 +17,6 @@ -->
    -
    -
    entity.no-data
    -
    widgets.invalid-qr-code-text
    -
    +
    entity.no-data
    +
    widgets.invalid-qr-code-text
    diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts index a7c2c46911..621a54da50 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts @@ -20,7 +20,7 @@ import { WidgetContext } from '@home/models/widget-component.models'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { - fillPattern, + fillPattern, flatData, parseData, parseFunction, processPattern, @@ -37,7 +37,7 @@ interface QrCodeWidgetSettings { qrCodeTextFunction: string; } -type QrCodeTextFunction = (data: FormattedData) => string; +type QrCodeTextFunction = (data: FormattedData[]) => string; @Component({ selector: 'tb-qrcode-widget', @@ -54,7 +54,6 @@ export class QrCodeWidgetComponent extends PageComponent implements OnInit, Afte qrCodeText: string; invalidQrCodeText = false; - datasourceDetected = false; private viewInited: boolean; private scheduleUpdateCanvas: boolean; @@ -97,17 +96,14 @@ export class QrCodeWidgetComponent extends PageComponent implements OnInit, Afte } ]; } else { - this.datasourceDetected = false; - } - if (initialData) { - const data = parseData(initialData); - const dataSourceData = data[0]; - const pattern = this.settings.useQrCodeTextFunction ? - safeExecute(this.qrCodeTextFunction, [dataSourceData]) : this.settings.qrCodeTextPattern; - const replaceInfo = processPattern(pattern, dataSourceData); - qrCodeText = fillPattern(pattern, replaceInfo, dataSourceData); - this.datasourceDetected = true; + initialData = []; } + const data = parseData(initialData); + const pattern = this.settings.useQrCodeTextFunction ? + safeExecute(this.qrCodeTextFunction, [data]) : this.settings.qrCodeTextPattern; + const allData = flatData(data); + const replaceInfo = processPattern(pattern, allData); + qrCodeText = fillPattern(pattern, replaceInfo, allData); this.updateQrCodeText(qrCodeText); } diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md new file mode 100644 index 0000000000..b3ea25d683 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md @@ -0,0 +1,58 @@ +#### Markdown text function + +
    +
    + +*function (data): string* + +A JavaScript function used to calculate markdown or HTML content. + +**Parameters:** + +
      +
    • data: FormattedData[] - An array of FormattedData objects resolved from configured datasources.
      + Each object represents basic entity properties (ex. entityId, entityName)
      and provides access to other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    + +**Returns:** + +Should return string value presenting markdown or HTML content. + +
    + +##### Examples + +* Display markdown with first entity name information: + +```javascript +return '# Some title\n - Entity name: ' + data[0]['entityName']; +{:copy-code} +``` + +
      +
    • +Display greetings for currently logged-in user.
      +Let's assume widget has first datasource configured using Current User Single entity alias
      +and has data keys for firstName, lastName and name entity fields: +
    • +
    + +```javascript +var userEntity = data[0]; +var userName; +if (userEntity.firstName || userEntity['First name']) { + userName = userEntity.firstName || userEntity['First name']; +} else if (userEntity.lastName || userEntity['Last name']) { + userName = userEntity.lastName || userEntity['Last name']; +} else if (userEntity.name || userEntity['Name']) { + userName = userEntity.name || userEntity['Name']; +} + +var welcomeText = 'Hi, ' + userName + '!\n\n'; +return welcomeText; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/qrcode/qrcode_text_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/qrcode/qrcode_text_fn.md new file mode 100644 index 0000000000..d119592030 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/qrcode/qrcode_text_fn.md @@ -0,0 +1,55 @@ +#### QR code text function + +
    +
    + +*function (data): string* + +A JavaScript function used to calculate text to be displayed as QR code. + +**Parameters:** + +
      +
    • data: FormattedData[] - An array of FormattedData objects resolved from configured datasources.
      + Each object represents basic entity properties (ex. entityId, entityName)
      and provides access to other entity attributes/timeseries declared in widget datasource configuration. +
    • +
    + +**Returns:** + +Should return string value presenting text to be displayed as QR code. + +
    + +##### Examples + +* Prepare QR code text from name of the first entity if present: + +```javascript +return data[0] ? data[0]['entityName'] : ''; +{:copy-code} +``` + +
      +
    • +Prepare QR code text to use as device claiming info (in this case {deviceName: string, secretKey: string}).
      +Let's assume device has claimingData attribute with string JSON value containing secretKey field
      +(see Claiming devices): +
    • +
    + +```javascript +var entityData = data[0]; +if (entityData) { + return JSON.stringify({ + deviceName: entityData.entityName, + secretKey: JSON.parse(entityData.claimingData).secretKey + }); +} else { + return ''; +} +{:copy-code} +``` + +
    +
    From 5fd155543f3d8e9ea88f27bc1a97b82a62275b06 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 20 Oct 2021 12:42:28 +0300 Subject: [PATCH 097/303] User controller --- .../server/controller/BaseController.java | 6 +- .../server/controller/DeviceController.java | 4 +- .../controller/DeviceProfileController.java | 6 +- .../controller/EntityQueryController.java | 4 +- .../server/controller/RpcV2Controller.java | 8 +- .../server/controller/TenantController.java | 4 +- .../controller/TenantProfileController.java | 5 - .../server/controller/UserController.java | 102 ++++++++++++++---- 8 files changed, 99 insertions(+), 40 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 542928b8bf..3beea19597 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -181,9 +181,9 @@ public abstract class BaseController { public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; - protected static final String SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; + protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority."; - protected static final String TENANT_AND_USER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; + protected static final String TENANT_OR_USER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -196,6 +196,7 @@ public abstract class BaseController { protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; + protected static final String USER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the user email."; protected static final String TENANT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant name."; protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant profile name."; protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name."; @@ -209,6 +210,7 @@ public abstract class BaseController { protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; protected static final String RPC_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, expirationTime, request, response"; protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; + protected static final String USER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, firstName, lastName, email"; protected static final String TENANT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, state, city, address, address2, zip, phone, email"; protected static final String TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault"; protected static final String TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; 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 0bbf1a6c8b..ac37d68304 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -103,8 +103,8 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get Device (getDeviceById)", notes = "Fetch the Device object based on the provided Device Id. " + - "If the user has the authority of 'Tenant Administrator', the server checks that the device is owned by the same tenant. " + - "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer.") + "If the user has the authority of 'TENANT_ADMIN', the server checks that the device is owned by the same tenant. " + + "If the user has the authority of 'CUSTOMER_USER', the server checks that the device is assigned to the same customer.") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index cae479814d..0fcad9a226 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -81,7 +81,7 @@ public class DeviceProfileController extends BaseController { @ApiOperation(value = "Get Device Profile Info (getDeviceProfileInfoById)", notes = "Fetch the Device Profile Info object based on the provided Device Profile Id. " - + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, + + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH, produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET) @@ -100,7 +100,7 @@ public class DeviceProfileController extends BaseController { @ApiOperation(value = "Get Default Device Profile (getDefaultDeviceProfileInfo)", notes = "Fetch the Default Device Profile Info object. " + - DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH, produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET) @@ -321,7 +321,7 @@ public class DeviceProfileController extends BaseController { @ApiOperation(value = "Get Device Profiles for transport type (getDeviceProfileInfos)", notes = "Returns a page of devices profile info objects owned by tenant. " + - PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, + PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH, produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 2e815bdc7e..8be2196ff6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -497,7 +497,7 @@ public class EntityQueryController extends BaseController { "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + ENTITY_FILTERS + KEY_FILTERS + - TENANT_AND_USER_AUTHORITY_PARAGRAPH;; + TENANT_OR_USER_AUTHORITY_PARAGRAPH;; private static final String ENTITY_DATA_QUERY_DESCRIPTION = "Allows to run complex queries over platform entities (devices, assets, customers, etc) " + @@ -580,7 +580,7 @@ public class EntityQueryController extends BaseController { "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + ENTITY_FILTERS + KEY_FILTERS + - TENANT_AND_USER_AUTHORITY_PARAGRAPH; + TENANT_OR_USER_AUTHORITY_PARAGRAPH; private static final String ALARM_DATA_QUERY_DESCRIPTION = "This method description defines how Alarm Data Query extends the Entity Data Query. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index 391f55f4fc..fa2d4b5ae7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -91,9 +91,9 @@ public class RpcV2Controller extends AbstractRpcController { "In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " + "the result of this call is the response from device, or 504 Gateway Timeout if device is offline."; - private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT + TENANT_AND_USER_AUTHORITY_PARAGRAPH; + private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT + TENANT_OR_USER_AUTHORITY_PARAGRAPH; - private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_AND_USER_AUTHORITY_PARAGRAPH; + private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_OR_USER_AUTHORITY_PARAGRAPH; @ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION) @ApiResponses(value = { @@ -131,7 +131,7 @@ public class RpcV2Controller extends AbstractRpcController { return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); } - @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call." + TENANT_AND_USER_AUTHORITY_PARAGRAPH) + @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call." + TENANT_OR_USER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET) @ResponseBody @@ -147,7 +147,7 @@ public class RpcV2Controller extends AbstractRpcController { } } - @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_AND_USER_AUTHORITY_PARAGRAPH) + @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_OR_USER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index e083c12440..d5c0b896c3 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -57,7 +57,7 @@ public class TenantController extends BaseController { private TenantService tenantService; @ApiOperation(value = "Get Tenant (getTenantById)", - notes = "Fetch the Tenant object based on the provided Tenant Id. " + SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH) + notes = "Fetch the Tenant object based on the provided Tenant Id. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.GET) @ResponseBody @@ -79,7 +79,7 @@ public class TenantController extends BaseController { @ApiOperation(value = "Get Tenant Info (getTenantInfoById)", notes = "Fetch the Tenant Info object based on the provided Tenant Id. " + - TENANT_INFO_DESCRIPTION + SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH) + TENANT_INFO_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/tenant/info/{tenantId}", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index 6223f750a5..e9b95e5d40 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -108,11 +108,6 @@ public class TenantProfileController extends BaseController { "Let's review the example of tenant profile data below: " + "\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + - " \"id\": {\n" + - " \"entityType\": \"TENANT_PROFILE\",\n" + - " \"id\": \"0f2978a0-0d46-11eb-ab90-09ceaa526dd8\"\n" + - " },\n" + - " \"createdTime\": 1602588011818,\n" + " \"name\": \"Default\",\n" + " \"description\": \"Default tenant profile\",\n" + " \"isolatedTbCore\": false,\n" + diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index 9daacc3027..f2362acb7f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -15,9 +15,9 @@ */ package org.thingsboard.server.controller; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; @@ -32,7 +32,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; @@ -52,6 +51,7 @@ import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEven import org.thingsboard.server.common.data.security.model.JwtToken; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; +import org.thingsboard.server.service.security.model.JwtTokenPair; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.UserPrincipal; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; @@ -82,20 +82,27 @@ public class UserController extends BaseController { private final SystemSecurityService systemSecurityService; private final ApplicationEventPublisher eventPublisher; + @ApiOperation(value = "Get User (getUserById)", + notes = "Fetch the User object based on the provided User Id. " + + "If the user has the authority of 'SYS_ADMIN', the server does not perform additional checks. " + + "If the user has the authority of 'TENANT_ADMIN', the server checks that the requested user is owned by the same tenant. " + + "If the user has the authority of 'CUSTOMER_USER', the server checks that the requested user is owned by the same customer.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET) @ResponseBody - public User getUserById(@PathVariable(USER_ID) String strUserId) throws ThingsboardException { + public User getUserById( + @ApiParam(value = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId) throws ThingsboardException { checkParameter(USER_ID, strUserId); try { UserId userId = new UserId(toUUID(strUserId)); User user = checkUserId(userId, Operation.READ); - if(user.getAdditionalInfo().isObject()) { + if (user.getAdditionalInfo().isObject()) { ObjectNode additionalInfo = (ObjectNode) user.getAdditionalInfo(); processDashboardIdFromAdditionalInfo(additionalInfo, DEFAULT_DASHBOARD); processDashboardIdFromAdditionalInfo(additionalInfo, HOME_DASHBOARD); UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId()); - if(userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) { + if (userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) { additionalInfo.put("userCredentialsEnabled", true); } } @@ -105,6 +112,10 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Check Token Access Enabled (isUserTokenAccessEnabled)", + notes = "Checks that the system is configured to allow administrators to impersonate themself as other users. " + + "If the user who performs the request has the authority of 'SYS_ADMIN', it is possible to login as any tenant administrator. " + + "If the user who performs the request has the authority of 'TENANT_ADMIN', it is possible to login as any customer user. ") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/user/tokenAccessEnabled", method = RequestMethod.GET) @ResponseBody @@ -112,10 +123,16 @@ public class UserController extends BaseController { return userTokenAccessEnabled; } + @ApiOperation(value = "Get User Token (getUserToken)", + notes = "Returns the token of the User based on the provided User Id. " + + "If the user who performs the request has the authority of 'SYS_ADMIN', it is possible to get the token of any tenant administrator. " + + "If the user who performs the request has the authority of 'TENANT_ADMIN', it is possible to get the token of any customer user that belongs to the same tenant. ") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/user/{userId}/token", method = RequestMethod.GET) @ResponseBody - public JsonNode getUserToken(@PathVariable(USER_ID) String strUserId) throws ThingsboardException { + public JwtTokenPair getUserToken( + @ApiParam(value = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId) throws ThingsboardException { checkParameter(USER_ID, strUserId); try { if (!userTokenAccessEnabled) { @@ -130,22 +147,26 @@ public class UserController extends BaseController { SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal); JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); - ObjectMapper objectMapper = new ObjectMapper(); - ObjectNode tokenObject = objectMapper.createObjectNode(); - tokenObject.put("token", accessToken.getToken()); - tokenObject.put("refreshToken", refreshToken.getToken()); - return tokenObject; + return new JwtTokenPair(accessToken.getToken(), refreshToken.getToken()); } catch (Exception e) { throw handleException(e); } } + @ApiOperation(value = "Save Or update User (saveUser)", + notes = "Create or update the User. When creating user, platform generates User Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created User Id will be present in the response. " + + "Specify existing User Id to update the device. " + + "Referencing non-existing User Id will cause 'Not Found' error." + + "\n\nDevice email is unique for entire platform setup.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/user", method = RequestMethod.POST) @ResponseBody - public User saveUser(@RequestBody User user, - @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, - HttpServletRequest request) throws ThingsboardException { + public User saveUser( + @ApiParam(value = "A JSON value representing the User.", required = true) + @RequestBody User user, + @ApiParam(value = "Send activation email (or use activation link)", defaultValue = "true") + @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, HttpServletRequest request) throws ThingsboardException { try { if (Authority.TENANT_ADMIN.equals(getCurrentUser().getAuthority())) { @@ -188,10 +209,13 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Send or re-send the activation email", + notes = "Force send the activation email to the user. Useful to resend the email if user has accidentally deleted it. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/user/sendActivationMail", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) public void sendActivationEmail( + @ApiParam(value = "Email of the user", required = true) @RequestParam(value = "email") String email, HttpServletRequest request) throws ThingsboardException { try { @@ -214,10 +238,14 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Get the activation link (getActivationLink)", + notes = "Get the activation link for the user. " + + "The base url for activation link is configurable in the general settings of system administrator. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/user/{userId}/activationLink", method = RequestMethod.GET, produces = "text/plain") @ResponseBody public String getActivationLink( + @ApiParam(value = USER_ID_PARAM_DESCRIPTION) @PathVariable(USER_ID) String strUserId, HttpServletRequest request) throws ThingsboardException { checkParameter(USER_ID, strUserId); @@ -239,10 +267,15 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Delete User (deleteUser)", + notes = "Deletes the User, it's credentials and all the relations (from and to the User). " + + "Referencing non-existing User Id will cause an error. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteUser(@PathVariable(USER_ID) String strUserId) throws ThingsboardException { + public void deleteUser( + @ApiParam(value = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId) throws ThingsboardException { checkParameter(USER_ID, strUserId); try { UserId userId = new UserId(toUUID(strUserId)); @@ -267,14 +300,22 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Get Users (getUsers)", + notes = "Returns a page of users owned by tenant or customer. The scope depends on authority of the user that performs the request." + + PAGE_DATA_PARAMETERS + TENANT_OR_USER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/users", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getUsers( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); @@ -289,15 +330,23 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Get Tenant Users (getTenantAdmins)", + notes = "Returns a page of users owned by tenant. " + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenant/{tenantId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getTenantAdmins( - @PathVariable("tenantId") String strTenantId, + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(TENANT_ID) String strTenantId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("tenantId", strTenantId); try { @@ -309,15 +358,23 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Get Customer Users (getCustomerUsers)", + notes = "Returns a page of users owned by customer. " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getCustomerUsers( - @PathVariable("customerId") String strCustomerId, + @ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(CUSTOMER_ID) String strCustomerId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("customerId", strCustomerId); try { @@ -331,11 +388,16 @@ public class UserController extends BaseController { } } + @ApiOperation(value = "Enable/Disable User credentials (setUserCredentialsEnabled)", + notes = "Enables or Disables user credentials. Useful when you would like to block user account without deleting it. " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/user/{userId}/userCredentialsEnabled", method = RequestMethod.POST) @ResponseBody - public void setUserCredentialsEnabled(@PathVariable(USER_ID) String strUserId, - @RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException { + public void setUserCredentialsEnabled( + @ApiParam(value = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId, + @ApiParam(value = "Disable (\"true\") or enable (\"false\") the credentials.", defaultValue = "true") + @RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException { checkParameter(USER_ID, strUserId); try { UserId userId = new UserId(toUUID(strUserId)); From 2ee26655da0bbe53f49c0b2a65a8459c722905f4 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 20 Oct 2021 13:34:33 +0300 Subject: [PATCH 098/303] Authority check info --- .../server/controller/AdminController.java | 15 +++-- .../server/controller/AlarmController.java | 18 +++--- .../server/controller/AssetController.java | 22 ++++--- .../server/controller/AuditLogController.java | 8 +-- .../server/controller/BaseController.java | 5 +- .../ComponentDescriptorController.java | 6 +- .../server/controller/CustomerController.java | 19 +++--- .../controller/DashboardController.java | 45 +++++++------- .../server/controller/DeviceController.java | 61 ++++++++++--------- .../controller/DeviceProfileController.java | 6 +- .../server/controller/EdgeController.java | 42 +++++++------ .../controller/EntityQueryController.java | 4 +- .../OAuth2ConfigTemplateController.java | 6 +- .../server/controller/OAuth2Controller.java | 6 +- .../server/controller/RpcV1Controller.java | 4 +- .../server/controller/RpcV2Controller.java | 8 +-- .../controller/RuleChainController.java | 13 ++-- .../controller/TelemetryController.java | 35 ++++++----- .../server/controller/UserController.java | 2 +- 19 files changed, 172 insertions(+), 153 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AdminController.java b/application/src/main/java/org/thingsboard/server/controller/AdminController.java index e896243f04..4284e3ca79 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AdminController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AdminController.java @@ -46,7 +46,6 @@ import org.thingsboard.server.service.update.UpdateService; @RequestMapping("/api/admin") public class AdminController extends BaseController { - public static final String SYS_ADMIN_AUTHORITY_ONLY = " Available for users with System Administrator ('SYS_ADMIN') authority only."; @Autowired private MailService mailService; @@ -63,7 +62,7 @@ public class AdminController extends BaseController { private UpdateService updateService; @ApiOperation(value = "Get the Administration Settings object using key (getAdminSettings)", - notes = "Get the Administration Settings object using specified string key. Referencing non-existing key will cause an error." + SYS_ADMIN_AUTHORITY_ONLY) + notes = "Get the Administration Settings object using specified string key. Referencing non-existing key will cause an error." + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/settings/{key}", method = RequestMethod.GET) @ResponseBody @@ -86,7 +85,7 @@ public class AdminController extends BaseController { @ApiOperation(value = "Get the Administration Settings object using key (getAdminSettings)", notes = "Creates or Updates the Administration Settings. Platform generates random Administration Settings Id during settings creation. " + "The Administration Settings Id will be present in the response. Specify the Administration Settings Id when you would like to update the Administration Settings. " + - "Referencing non-existing Administration Settings Id will cause an error." + SYS_ADMIN_AUTHORITY_ONLY) + "Referencing non-existing Administration Settings Id will cause an error." + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/settings", method = RequestMethod.POST) @ResponseBody @@ -109,7 +108,7 @@ public class AdminController extends BaseController { } @ApiOperation(value = "Get the Security Settings object", - notes = "Get the Security Settings object that contains password policy, etc." + SYS_ADMIN_AUTHORITY_ONLY) + notes = "Get the Security Settings object that contains password policy, etc." + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/securitySettings", method = RequestMethod.GET) @ResponseBody @@ -123,7 +122,7 @@ public class AdminController extends BaseController { } @ApiOperation(value = "Update Security Settings (saveSecuritySettings)", - notes = "Updates the Security Settings object that contains password policy, etc." + SYS_ADMIN_AUTHORITY_ONLY) + notes = "Updates the Security Settings object that contains password policy, etc." + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/securitySettings", method = RequestMethod.POST) @ResponseBody @@ -141,7 +140,7 @@ public class AdminController extends BaseController { @ApiOperation(value = "Send test email (sendTestMail)", notes = "Attempts to send test email to the System Administrator User using Mail Settings provided as a parameter. " + - "You may change the 'To' email in the user profile of the System Administrator. " + SYS_ADMIN_AUTHORITY_ONLY) + "You may change the 'To' email in the user profile of the System Administrator. " + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/settings/testMail", method = RequestMethod.POST) public void sendTestMail( @@ -165,7 +164,7 @@ public class AdminController extends BaseController { @ApiOperation(value = "Send test sms (sendTestMail)", notes = "Attempts to send test sms to the System Administrator User using SMS Settings and phone number provided as a parameters of the request. " - + SYS_ADMIN_AUTHORITY_ONLY) + + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/settings/testSms", method = RequestMethod.POST) public void sendTestSms( @@ -181,7 +180,7 @@ public class AdminController extends BaseController { @ApiOperation(value = "Check for new Platform Releases (checkUpdates)", notes = "Check notifications about new platform releases. " - + SYS_ADMIN_AUTHORITY_ONLY) + + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/updates", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index a0942ab8ff..b5a892df57 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -88,7 +88,7 @@ public class AlarmController extends BaseController { @ApiOperation(value = "Get Alarm Info (getAlarmInfoById)", notes = "Fetch the Alarm Info object based on the provided Alarm Id. " + - ALARM_SECURITY_CHECK + ALARM_INFO_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) + ALARM_SECURITY_CHECK + ALARM_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/info/{alarmId}", method = RequestMethod.GET) @ResponseBody @@ -111,7 +111,7 @@ public class AlarmController extends BaseController { "\n\nPlatform also deduplicate the alarms based on the entity id of originator and alarm 'type'. " + "For example, if the user or system component create the alarm with the type 'HighTemperature' for device 'Device A' the new active alarm is created. " + "If the user tries to create 'HighTemperature' alarm for the same device again, the previous alarm will be updated (the 'end_ts' will be set to current timestamp). " + - "If the user clears the alarm (see 'Clear Alarm(clearAlarm)'), than new alarm with the same type and same device may be created. " + "If the user clears the alarm (see 'Clear Alarm(clearAlarm)'), than new alarm with the same type and same device may be created. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH , produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm", method = RequestMethod.POST) @@ -138,7 +138,7 @@ public class AlarmController extends BaseController { } @ApiOperation(value = "Delete Alarm (deleteAlarm)", - notes = "Deletes the Alarm. Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Deletes the Alarm. Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.DELETE) @ResponseBody @@ -165,7 +165,7 @@ public class AlarmController extends BaseController { @ApiOperation(value = "Acknowledge Alarm (ackAlarm)", notes = "Acknowledge the Alarm. " + "Once acknowledged, the 'ack_ts' field will be set to current timestamp and special rule chain event 'ALARM_ACK' will be generated. " + - "Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + "Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @@ -189,7 +189,7 @@ public class AlarmController extends BaseController { @ApiOperation(value = "Clear Alarm (clearAlarm)", notes = "Clear the Alarm. " + "Once cleared, the 'clear_ts' field will be set to current timestamp and special rule chain event 'ALARM_CLEAR' will be generated. " + - "Referencing non-existing Alarm Id will cause an error.", produces = MediaType.APPLICATION_JSON_VALUE) + "Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @@ -212,8 +212,8 @@ public class AlarmController extends BaseController { @ApiOperation(value = "Get Alarms (getAlarms)", notes = "Returns a page of alarms for the selected entity. Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error. " + - PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET) @ResponseBody public PageData getAlarms( @@ -265,7 +265,7 @@ public class AlarmController extends BaseController { "If the user has the authority of 'Tenant Administrator', the server returns alarms that belongs to the tenant of current user. " + "If the user has the authority of 'Customer User', the server returns alarms that belongs to the customer of current user. " + "Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error. " + - PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarms", method = RequestMethod.GET) @ResponseBody @@ -312,7 +312,7 @@ public class AlarmController extends BaseController { @ApiOperation(value = "Get Highest Alarm Severity (getHighestAlarmSeverity)", notes = "Search the alarms by originator ('entityType' and entityId') and optional 'status' or 'searchStatus' filters and returns the highest AlarmSeverity(CRITICAL, MAJOR, MINOR, WARNING or INDETERMINATE). " + - "Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error." + "Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH , produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET) diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index de57573c7a..2e3e327ced 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -80,7 +80,8 @@ public class AssetController extends BaseController { @ApiOperation(value = "Get Asset (getAssetById)", notes = "Fetch the Asset object based on the provided Asset Id. " + "If the user has the authority of 'Tenant Administrator', the server checks that the asset is owned by the same tenant. " + - "If the user has the authority of 'Customer User', the server checks that the asset is assigned to the same customer.", produces = MediaType.APPLICATION_JSON_VALUE) + "If the user has the authority of 'Customer User', the server checks that the asset is assigned to the same customer." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH + , produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/asset/{assetId}", method = RequestMethod.GET) @ResponseBody @@ -98,7 +99,8 @@ public class AssetController extends BaseController { @ApiOperation(value = "Get Asset Info (getAssetInfoById)", notes = "Fetch the Asset Info object based on the provided Asset Id. " + "If the user has the authority of 'Tenant Administrator', the server checks that the asset is owned by the same tenant. " + - "If the user has the authority of 'Customer User', the server checks that the asset is assigned to the same customer. " + ASSET_INFO_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) + "If the user has the authority of 'Customer User', the server checks that the asset is assigned to the same customer. " + + ASSET_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/asset/info/{assetId}", method = RequestMethod.GET) @ResponseBody @@ -117,7 +119,7 @@ public class AssetController extends BaseController { notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address) " + "The newly created Asset id will be present in the response. " + "Specify existing Asset id to update the asset. " + - "Referencing non-existing Asset Id will cause 'Not Found' error.", produces = MediaType.APPLICATION_JSON_VALUE) + "Referencing non-existing Asset Id will cause 'Not Found' error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/asset", method = RequestMethod.POST) @ResponseBody @@ -158,7 +160,7 @@ public class AssetController extends BaseController { } @ApiOperation(value = "Delete asset (deleteAsset)", - notes = "Deletes the asset and all the relations (from and to the asset). Referencing non-existing asset Id will cause an error.") + notes = "Deletes the asset and all the relations (from and to the asset). Referencing non-existing asset Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/asset/{assetId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -187,7 +189,7 @@ public class AssetController extends BaseController { } @ApiOperation(value = "Assign asset to customer (assignAssetToCustomer)", - notes = "Creates assignment of the asset to customer. Customer will be able to query asset afterwards.", produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Creates assignment of the asset to customer. Customer will be able to query asset afterwards." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/asset/{assetId}", method = RequestMethod.POST) @ResponseBody @@ -223,7 +225,7 @@ public class AssetController extends BaseController { } @ApiOperation(value = "Unassign asset from customer (unassignAssetFromCustomer)", - notes = "Clears assignment of the asset to customer. Customer will not be able to query asset afterwards.", produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Clears assignment of the asset to customer. Customer will not be able to query asset afterwards." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/asset/{assetId}", method = RequestMethod.DELETE) @ResponseBody @@ -261,7 +263,7 @@ public class AssetController extends BaseController { @ApiOperation(value = "Make asset publicly available (assignAssetToPublicCustomer)", notes = "Asset will be available for non-authorized (not logged-in) users. " + "This is useful to create dashboards that you plan to share/embed on a publicly available website. " + - "However, users that are logged-in and belong to different tenant will not be able to access the asset.", produces = MediaType.APPLICATION_JSON_VALUE) + "However, users that are logged-in and belong to different tenant will not be able to access the asset." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/asset/{assetId}", method = RequestMethod.POST) @ResponseBody @@ -290,7 +292,7 @@ public class AssetController extends BaseController { @ApiOperation(value = "Get Tenant Assets (getTenantAssets)", notes = "Returns a page of assets owned by tenant. " + - PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/assets", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -322,7 +324,7 @@ public class AssetController extends BaseController { @ApiOperation(value = "Get Tenant Asset Infos (getTenantAssetInfos)", notes = "Returns a page of assets info objects owned by tenant. " + - PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) + PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -354,7 +356,7 @@ public class AssetController extends BaseController { @ApiOperation(value = "Get Tenant Asset (getTenantAsset)", notes = "Requested asset must be owned by tenant that the user belongs to. " + - "Asset name is an unique property of asset. So it can be used to identify the asset.", produces = MediaType.APPLICATION_JSON_VALUE) + "Asset name is an unique property of asset. So it can be used to identify the asset." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java index afc9e6a376..5f71c0950c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java @@ -60,7 +60,7 @@ public class AuditLogController extends BaseController { @ApiOperation(value = "Get audit logs by customer id (getAuditLogsByCustomerId)", notes = "Returns a page of audit logs related to the targeted customer entities (devices, assets, etc.), " + "and users actions (login, logout, etc.) that belong to this customer. " + - PAGE_DATA_PARAMETERS + ADMINISTRATOR_AUTHORITY_ONLY, + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -98,7 +98,7 @@ public class AuditLogController extends BaseController { @ApiOperation(value = "Get audit logs by user id (getAuditLogsByUserId)", notes = "Returns a page of audit logs related to the actions of targeted user. " + "For example, RPC call to a particular device, or alarm acknowledgment for a specific device, etc. " + - PAGE_DATA_PARAMETERS + ADMINISTRATOR_AUTHORITY_ONLY, + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/user/{userId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -137,7 +137,7 @@ public class AuditLogController extends BaseController { notes = "Returns a page of audit logs related to the actions on the targeted entity. " + "Basically, this API call is used to get the full lifecycle of some specific entity. " + "For example to see when a device was created, updated, assigned to some customer, or even deleted from the system. " + - PAGE_DATA_PARAMETERS + ADMINISTRATOR_AUTHORITY_ONLY, + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -177,7 +177,7 @@ public class AuditLogController extends BaseController { @ApiOperation(value = "Get all audit logs (getAuditLogs)", notes = "Returns a page of audit logs related to all entities in the scope of the current user's Tenant. " + - PAGE_DATA_PARAMETERS + ADMINISTRATOR_AUTHORITY_ONLY, + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/audit/logs", params = {"pageSize", "page"}, method = RequestMethod.GET) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 3beea19597..82dc85e978 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -183,7 +183,8 @@ public abstract class BaseController { protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority."; - protected static final String TENANT_OR_USER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; + protected static final String TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; + protected static final String CUSTOMER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'CUSTOMER_USER' authority."; protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -262,8 +263,6 @@ public abstract class BaseController { protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; - protected static final String ADMINISTRATOR_AUTHORITY_ONLY = "Available for users with 'Tenant Administrator' authority only."; - public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; protected static final String HOME_DASHBOARD = "homeDashboardId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java index a2bb902dad..0cd657466b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java +++ b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java @@ -47,7 +47,7 @@ public class ComponentDescriptorController extends BaseController { @ApiOperation(value = "Get Component Descriptor (getComponentDescriptorByClazz)", notes = "Gets the Component Descriptor object using class name from the path parameters. " + - COMPONENT_DESCRIPTOR_DEFINITION) + COMPONENT_DESCRIPTOR_DEFINITION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") @RequestMapping(value = "/component/{componentDescriptorClazz:.+}", method = RequestMethod.GET) @ResponseBody @@ -64,7 +64,7 @@ public class ComponentDescriptorController extends BaseController { @ApiOperation(value = "Get Component Descriptors (getComponentDescriptorsByType)", notes = "Gets the Component Descriptors using rule node type and optional rule chain type request parameters. " + - COMPONENT_DESCRIPTOR_DEFINITION) + COMPONENT_DESCRIPTOR_DEFINITION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") @RequestMapping(value = "/components/{componentType}", method = RequestMethod.GET) @ResponseBody @@ -83,7 +83,7 @@ public class ComponentDescriptorController extends BaseController { @ApiOperation(value = "Get Component Descriptors (getComponentDescriptorsByTypes)", notes = "Gets the Component Descriptors using coma separated list of rule node types and optional rule chain type request parameters. " + - COMPONENT_DESCRIPTOR_DEFINITION) + COMPONENT_DESCRIPTOR_DEFINITION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") @RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index d1c5610bf0..d6d248a57c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -57,7 +57,8 @@ public class CustomerController extends BaseController { "If the user has the authority of 'Customer User', the server checks that the user belongs to the customer."; @ApiOperation(value = "Get Customer (getCustomerById)", - notes = "Get the Customer object based on the provided Customer Id. " + CUSTOMER_SECURITY_CHECK) + notes = "Get the Customer object based on the provided Customer Id. " + + CUSTOMER_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}", method = RequestMethod.GET) @ResponseBody @@ -79,7 +80,8 @@ public class CustomerController extends BaseController { @ApiOperation(value = "Get short Customer info (getShortCustomerInfoById)", - notes = "Get the short customer object that contains only the title and 'isPublic' flag. " + CUSTOMER_SECURITY_CHECK) + notes = "Get the short customer object that contains only the title and 'isPublic' flag. " + + CUSTOMER_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/shortInfo", method = RequestMethod.GET) @ResponseBody @@ -101,7 +103,8 @@ public class CustomerController extends BaseController { } @ApiOperation(value = "Get Customer Title (getCustomerTitleById)", - notes = "Get the title of the customer. " + CUSTOMER_SECURITY_CHECK) + notes = "Get the title of the customer. " + + CUSTOMER_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/title", method = RequestMethod.GET, produces = "application/text") @ResponseBody @@ -122,7 +125,7 @@ public class CustomerController extends BaseController { notes = "Creates or Updates the Customer. When creating customer, platform generates Customer Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address) " + "The newly created Customer Id will be present in the response. " + "Specify existing Customer Id to update the Customer. " + - "Referencing non-existing Customer Id will cause 'Not Found' error.") + "Referencing non-existing Customer Id will cause 'Not Found' error." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer", method = RequestMethod.POST) @ResponseBody @@ -153,7 +156,9 @@ public class CustomerController extends BaseController { } @ApiOperation(value = "Delete Customer (deleteCustomer)", - notes = "Deletes the Customer and all customer Users. All assigned Dashboards, Assets, Devices, etc. will be unassigned but not deleted. Referencing non-existing Customer Id will cause an error.") + notes = "Deletes the Customer and all customer Users. " + + "All assigned Dashboards, Assets, Devices, etc. will be unassigned but not deleted. " + + "Referencing non-existing Customer Id will cause an error." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -187,7 +192,7 @@ public class CustomerController extends BaseController { @ApiOperation(value = "Get Tenant Customers (getCustomers)", notes = "Returns a page of customers owned by tenant. " + - PAGE_DATA_PARAMETERS) + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customers", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -212,7 +217,7 @@ public class CustomerController extends BaseController { } @ApiOperation(value = "Get Tenant Customer by Customer title (getTenantCustomer)", - notes = "Get the Customer using Customer Title. " + ADMINISTRATOR_AUTHORITY_ONLY) + notes = "Get the Customer using Customer Title. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/customers", params = {"customerTitle"}, method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index c84b4d0eaa..11b5fa0727 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -120,7 +120,7 @@ public class DashboardController extends BaseController { } @ApiOperation(value = "Get Dashboard (getDashboardById)", - notes = "Get the dashboard based on 'dashboardId' parameter. " + DASHBOARD_DEFINITION, + notes = "Get the dashboard based on 'dashboardId' parameter. " + DASHBOARD_DEFINITION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE ) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @@ -143,7 +143,7 @@ public class DashboardController extends BaseController { "The newly created Dashboard id will be present in the response. " + "Specify existing Dashboard id to update the dashboard. " + "Referencing non-existing dashboard Id will cause 'Not Found' error. " + - "Only users with 'TENANT_ADMIN') authority may create the dashboards.", + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -177,7 +177,7 @@ public class DashboardController extends BaseController { } @ApiOperation(value = "Delete the Dashboard (deleteDashboard)", - notes = "Delete the Dashboard. Only users with 'TENANT_ADMIN') authority may delete the dashboards.") + notes = "Delete the Dashboard." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -211,7 +211,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Assign the Dashboard (assignDashboardToCustomer)", notes = "Assign the Dashboard to specified Customer or do nothing if the Dashboard is already assigned to that Customer. " + - "Returns the Dashboard object. Only users with 'TENANT_ADMIN') authority may assign the dashboards to customers.", + "Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.POST) @@ -251,7 +251,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Unassign the Dashboard (unassignDashboardFromCustomer)", notes = "Unassign the Dashboard from specified Customer or do nothing if the Dashboard is already assigned to that Customer. " + - "Returns the Dashboard object. Only users with 'TENANT_ADMIN') authority may unassign the dashboards from customers.", + "Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.DELETE) @@ -290,7 +290,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Update the Dashboard Customers (updateDashboardCustomers)", notes = "Updates the list of Customers that this Dashboard is assigned to. Removes previous assignments to customers that are not in the provided list. " + - "Returns the Dashboard object. Only users with 'TENANT_ADMIN') authority may assign the dashboards to customers.", + "Returns the Dashboard object. " + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @@ -365,7 +365,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Adds the Dashboard Customers (addDashboardCustomers)", notes = "Adds the list of Customers to the existing list of assignments for the Dashboard. Keeps previous assignments to customers that are not in the provided list. " + - "Returns the Dashboard object. Only users with 'TENANT_ADMIN') authority may assign the dashboards to customers.", + "Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -417,7 +417,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Remove the Dashboard Customers (removeDashboardCustomers)", notes = "Removes the list of Customers from the existing list of assignments for the Dashboard. Keeps other assignments to customers that are not in the provided list. " + - "Returns the Dashboard object. Only users with 'TENANT_ADMIN') authority may assign the dashboards to customers.", + "Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -473,7 +473,7 @@ public class DashboardController extends BaseController { "Be aware that making the dashboard public does not mean that it automatically makes all devices and assets you use in the dashboard to be public." + "Use [assign Asset to Public Customer](#!/asset-controller/assignAssetToPublicCustomerUsingPOST) and " + "[assign Device to Public Customer](#!/device-controller/assignDeviceToPublicCustomerUsingPOST) for this purpose. " + - "Returns the Dashboard object. Only users with 'TENANT_ADMIN') authority may assign the dashboards to customers.", + "Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/dashboard/{dashboardId}", method = RequestMethod.POST) @@ -505,7 +505,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Unassign the Dashboard from Public Customer (unassignDashboardFromPublicCustomer)", notes = "Unassigns the dashboard from a special, auto-generated 'Public' Customer. Once unassigned, unauthenticated users may no longer browse the dashboard. " + - "Returns the Dashboard object. Only users with 'TENANT_ADMIN') authority may assign the dashboards to customers.", + "Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/dashboard/{dashboardId}", method = RequestMethod.DELETE) @@ -538,7 +538,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Get Tenant Dashboards by System Administrator (getTenantDashboards)", notes = "Returns a page of dashboard info objects owned by tenant. " + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + - "Only users with 'SYS_ADMIN' authority may use this method.", + SYSTEM_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('SYS_ADMIN')") @RequestMapping(value = "/tenant/{tenantId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -567,8 +567,8 @@ public class DashboardController extends BaseController { } @ApiOperation(value = "Get Tenant Dashboards (getTenantDashboards)", - notes = "Returns a page of dashboard info objects owned by the tenant of a current user. " + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + - "Only users with 'TENANT_ADMIN' authority may use this method.", + notes = "Returns a page of dashboard info objects owned by the tenant of a current user. " + + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -600,8 +600,8 @@ public class DashboardController extends BaseController { } @ApiOperation(value = "Get Customer Dashboards (getCustomerDashboards)", - notes = "Returns a page of dashboard info objects owned by the specified customer. " + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + - "Only users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority may use this method.", + notes = "Returns a page of dashboard info objects owned by the specified customer. " + + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -641,8 +641,7 @@ public class DashboardController extends BaseController { notes = "Returns the home dashboard object that is configured as 'homeDashboardId' parameter in the 'additionalInfo' of the User. " + "If 'homeDashboardId' parameter is not set on the User level and the User has authority 'CUSTOMER_USER', check the same parameter for the corresponding Customer. " + "If 'homeDashboardId' parameter is not set on the User and Customer levels then checks the same parameter for the Tenant that owns the user. " - + DASHBOARD_DEFINITION + " " + - "Only users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority should use this method.", + + DASHBOARD_DEFINITION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("isAuthenticated()") @RequestMapping(value = "/dashboard/home", method = RequestMethod.GET) @@ -679,7 +678,7 @@ public class DashboardController extends BaseController { notes = "Returns the home dashboard info object that is configured as 'homeDashboardId' parameter in the 'additionalInfo' of the User. " + "If 'homeDashboardId' parameter is not set on the User level and the User has authority 'CUSTOMER_USER', check the same parameter for the corresponding Customer. " + "If 'homeDashboardId' parameter is not set on the User and Customer levels then checks the same parameter for the Tenant that owns the user. " + - "Only users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority should use this method.", + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("isAuthenticated()") @RequestMapping(value = "/dashboard/home/info", method = RequestMethod.GET) @@ -714,7 +713,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Get Tenant Home Dashboard Info (getTenantHomeDashboardInfo)", notes = "Returns the home dashboard info object that is configured as 'homeDashboardId' parameter in the 'additionalInfo' of the corresponding tenant. " + - "Only users with 'TENANT_ADMIN' authority may use this method.", + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.GET) @@ -740,7 +739,7 @@ public class DashboardController extends BaseController { @ApiOperation(value = "Update Tenant Home Dashboard Info (getTenantHomeDashboardInfo)", notes = "Update the home dashboard assignment for the current tenant. " + - "Only users with 'TENANT_ADMIN' authority may use this method.", + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.POST) @@ -810,7 +809,8 @@ public class DashboardController extends BaseController { EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive a copy of assignment dashboard " + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + - "Third, once dashboard will be delivered to edge service, it's going to be available for usage on remote edge instance.", + "Third, once dashboard will be delivered to edge service, it's going to be available for usage on remote edge instance." + + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.POST) @@ -850,7 +850,8 @@ public class DashboardController extends BaseController { EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive an 'unassign' command to remove dashboard " + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + - "Third, once 'unassign' command will be delivered to edge service, it's going to remove dashboard locally.", + "Third, once 'unassign' command will be delivered to edge service, it's going to remove dashboard locally." + + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.DELETE) 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 ac37d68304..46262b6f30 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -104,7 +104,8 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get Device (getDeviceById)", notes = "Fetch the Device object based on the provided Device Id. " + "If the user has the authority of 'TENANT_ADMIN', the server checks that the device is owned by the same tenant. " + - "If the user has the authority of 'CUSTOMER_USER', the server checks that the device is assigned to the same customer.") + "If the user has the authority of 'CUSTOMER_USER', the server checks that the device is assigned to the same customer." + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) @ResponseBody @@ -122,7 +123,8 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get Device Info (getDeviceInfoById)", notes = "Fetch the Device Info object based on the provided Device Id. " + "If the user has the authority of 'Tenant Administrator', the server checks that the device is owned by the same tenant. " + - "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer. " + DEVICE_INFO_DESCRIPTION) + "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer. " + + DEVICE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device/info/{deviceId}", method = RequestMethod.GET) @ResponseBody @@ -139,11 +141,12 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Create Or Update Device (saveDevice)", notes = "Create or update the Device. When creating device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + - "Device credentials are also generated if not provided in the 'accessToken' request parameter. " + - "The newly created device id will be present in the response. " + - "Specify existing Device id to update the device. " + - "Referencing non-existing device Id will cause 'Not Found' error." + - "\n\nDevice name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the device names and non-unique 'label' field for user-friendly visualization purposes.") + "Device credentials are also generated if not provided in the 'accessToken' request parameter. " + + "The newly created device id will be present in the response. " + + "Specify existing Device id to update the device. " + + "Referencing non-existing device Id will cause 'Not Found' error." + + "\n\nDevice name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the device names and non-unique 'label' field for user-friendly visualization purposes." + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device", method = RequestMethod.POST) @ResponseBody @@ -187,7 +190,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Delete device (deleteDevice)", - notes = "Deletes the device, it's credentials and all the relations (from and to the device). Referencing non-existing device Id will cause an error.") + notes = "Deletes the device, it's credentials and all the relations (from and to the device). Referencing non-existing device Id will cause an error." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -219,7 +222,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Assign device to customer (assignDeviceToCustomer)", - notes = "Creates assignment of the device to customer. Customer will be able to query device afterwards.") + notes = "Creates assignment of the device to customer. Customer will be able to query device afterwards." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/device/{deviceId}", method = RequestMethod.POST) @ResponseBody @@ -255,7 +258,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Unassign device from customer (unassignDeviceFromCustomer)", - notes = "Clears assignment of the device to customer. Customer will not be able to query device afterwards.") + notes = "Clears assignment of the device to customer. Customer will not be able to query device afterwards." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/device/{deviceId}", method = RequestMethod.DELETE) @ResponseBody @@ -291,7 +294,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Make device publicly available (assignDeviceToPublicCustomer)", notes = "Device will be available for non-authorized (not logged-in) users. " + "This is useful to create dashboards that you plan to share/embed on a publicly available website. " + - "However, users that are logged-in and belong to different tenant will not be able to access the device.") + "However, users that are logged-in and belong to different tenant will not be able to access the device." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/device/{deviceId}", method = RequestMethod.POST) @ResponseBody @@ -318,7 +321,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Get Device Credentials (getDeviceCredentialsByDeviceId)", - notes = "If during device creation there wasn't specified any credentials, platform generates random 'ACCESS_TOKEN' credentials.") + notes = "If during device creation there wasn't specified any credentials, platform generates random 'ACCESS_TOKEN' credentials." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device/{deviceId}/credentials", method = RequestMethod.GET) @ResponseBody @@ -344,7 +347,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Update device credentials (updateDeviceCredentials)", notes = "During device creation, platform generates random 'ACCESS_TOKEN' credentials. " + "Use this method to update the device credentials. First use 'getDeviceCredentialsByDeviceId' to get the credentials id and value. " + "Then use current method to update the credentials type and value. It is not possible to create multiple device credentials for the same device. " + - "The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'.") + "The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/device/credentials", method = RequestMethod.POST) @ResponseBody @@ -405,7 +408,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get Tenant Device Infos (getTenantDeviceInfos)", notes = "Returns a page of devices info objects owned by tenant. " + - PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION) + PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/deviceInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -443,7 +446,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get Tenant Device (getTenantDevice)", notes = "Requested device must be owned by tenant that the user belongs to. " + - "Device name is an unique property of device. So it can be used to identify the device.") + "Device name is an unique property of device. So it can be used to identify the device." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/devices", params = {"deviceName"}, method = RequestMethod.GET) @ResponseBody @@ -460,7 +463,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get Customer Devices (getCustomerDevices)", notes = "Returns a page of devices objects assigned to customer. " + - PAGE_DATA_PARAMETERS) + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -497,7 +500,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get Customer Device Infos (getCustomerDeviceInfos)", notes = "Returns a page of devices info objects assigned to customer. " + - PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION) + PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/deviceInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -538,7 +541,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Get Devices By Ids (getDevicesByIds)", - notes = "Requested devices must be owned by tenant or assigned to customer which user is performing the request. ") + notes = "Requested devices must be owned by tenant or assigned to customer which user is performing the request. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/devices", params = {"deviceIds"}, method = RequestMethod.GET) @ResponseBody @@ -569,7 +572,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Find related devices (findByQuery)", notes = "Returns all devices that are related to the specific entity. " + "The entity id, relation type, device types, depth of the search, and other query parameters defined using complex 'DeviceSearchQuery' object. " + - "See 'Model' tab of the Parameters for more info.") + "See 'Model' tab of the Parameters for more info." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/devices", method = RequestMethod.POST) @ResponseBody @@ -597,7 +600,8 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Get Device Types (getDeviceTypes)", - notes = "Returns a set of unique device profile names based on devices that are either owned by the tenant or assigned to the customer which user is performing the request.") + notes = "Returns a set of unique device profile names based on devices that are either owned by the tenant or assigned to the customer which user is performing the request." + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device/types", method = RequestMethod.GET) @ResponseBody @@ -618,7 +622,7 @@ public class DeviceController extends BaseController { "Once device is claimed, the customer becomes its owner and customer users may access device data as well as control the device. \n" + "In order to enable claiming devices feature a system parameter security.claim.allowClaimingByDefault should be set to true, " + "otherwise a server-side claimingAllowed attribute with the value true is obligatory for provisioned devices. \n" + - "See official documentation for more details regarding claiming.") + "See official documentation for more details regarding claiming." + CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('CUSTOMER_USER')") @RequestMapping(value = "/customer/device/{deviceName}/claim", method = RequestMethod.POST) @ResponseBody @@ -676,7 +680,8 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Reclaim device (reClaimDevice)", - notes = "Reclaiming means the device will be unassigned from the customer and the device will be available for claiming again.") + notes = "Reclaiming means the device will be unassigned from the customer and the device will be available for claiming again." + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/device/{deviceName}/claim", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -730,7 +735,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Assign device to tenant (assignDeviceToTenant)", - notes = "Creates assignment of the device to tenant. Thereafter tenant will be able to reassign the device to a customer.") + notes = "Creates assignment of the device to tenant. Thereafter tenant will be able to reassign the device to a customer." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/{tenantId}/device/{deviceId}", method = RequestMethod.POST) @ResponseBody @@ -788,7 +793,7 @@ public class DeviceController extends BaseController { EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive a copy of assignment device " + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + - "Third, once device will be delivered to edge service, it's going to be available for usage on remote edge instance.", + "Third, once device will be delivered to edge service, it's going to be available for usage on remote edge instance." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.POST) @@ -831,7 +836,7 @@ public class DeviceController extends BaseController { EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive an 'unassign' command to remove device " + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + - "Third, once 'unassign' command will be delivered to edge service, it's going to remove device locally.", + "Third, once 'unassign' command will be delivered to edge service, it's going to remove device locally." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.DELETE) @@ -871,7 +876,7 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Get devices assigned to edge (getEdgeDevices)", notes = "Returns a page of devices assigned to edge. " + - PAGE_DATA_PARAMETERS) + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/{edgeId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -928,7 +933,7 @@ public class DeviceController extends BaseController { notes = "The platform gives an ability to load OTA (over-the-air) packages to devices. " + "It can be done in two different ways: device scope or device profile scope." + "In the response you will find the number of devices with specified device profile, but without previously defined device scope OTA package. " + - "It can be useful when you want to define number of devices that will be affected with future OTA package") + "It can be useful when you want to define number of devices that will be affected with future OTA package" + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/devices/count/{otaPackageType}/{deviceProfileId}", method = RequestMethod.GET) @ResponseBody @@ -949,7 +954,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Import the bulk of devices (processDevicesBulkImport)", - notes = "There's an ability to import the bulk of devices using the only .csv file.") + notes = "There's an ability to import the bulk of devices using the only .csv file." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PostMapping("/device/bulk_import") public BulkImportResult processDevicesBulkImport(@RequestBody BulkImportRequest request) throws Exception { diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 0fcad9a226..71719531d5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -81,7 +81,7 @@ public class DeviceProfileController extends BaseController { @ApiOperation(value = "Get Device Profile Info (getDeviceProfileInfoById)", notes = "Fetch the Device Profile Info object based on the provided Device Profile Id. " - + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH, + + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET) @@ -100,7 +100,7 @@ public class DeviceProfileController extends BaseController { @ApiOperation(value = "Get Default Device Profile (getDefaultDeviceProfileInfo)", notes = "Fetch the Default Device Profile Info object. " + - DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH, + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET) @@ -321,7 +321,7 @@ public class DeviceProfileController extends BaseController { @ApiOperation(value = "Get Device Profiles for transport type (getDeviceProfileInfos)", notes = "Returns a page of devices profile info objects owned by tenant. " + - PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH, + PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 2121fdc3ec..d518c6e201 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -91,7 +91,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Get Edge (getEdgeById)", - notes = "Get the Edge object based on the provided Edge Id. " + EDGE_SECURITY_CHECK, + notes = "Get the Edge object based on the provided Edge Id. " + EDGE_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET) @@ -112,7 +112,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Get Edge Info (getEdgeInfoById)", - notes = "Get the Edge Info object based on the provided Edge Id. " + EDGE_SECURITY_CHECK, + notes = "Get the Edge Info object based on the provided Edge Id. " + EDGE_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/info/{edgeId}", method = RequestMethod.GET) @@ -137,7 +137,8 @@ public class EdgeController extends BaseController { "The newly created edge id will be present in the response. " + "Specify existing Edge id to update the edge. " + "Referencing non-existing Edge Id will cause 'Not Found' error." + - "\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes.", + "\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes." + + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge", method = RequestMethod.POST) @@ -187,7 +188,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Delete edge (deleteEdge)", - notes = "Deletes the edge. Referencing non-existing edge Id will cause an error.") + notes = "Deletes the edge. Referencing non-existing edge Id will cause an error."+ TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -219,7 +220,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Tenant Edges (getEdges)", notes = "Returns a page of edges owned by tenant. " + - PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -243,7 +244,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Assign edge to customer (assignEdgeToCustomer)", - notes = "Creates assignment of the edge to customer. Customer will be able to query edge afterwards.", + notes = "Creates assignment of the edge to customer. Customer will be able to query edge afterwards." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST) @@ -283,7 +284,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Unassign edge from customer (unassignEdgeFromCustomer)", - notes = "Clears assignment of the edge to customer. Customer will not be able to query edge afterwards.", + notes = "Clears assignment of the edge to customer. Customer will not be able to query edge afterwards." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE) @@ -323,7 +324,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Make edge publicly available (assignEdgeToPublicCustomer)", notes = "Edge will be available for non-authorized (not logged-in) users. " + "This is useful to create dashboards that you plan to share/embed on a publicly available website. " + - "However, users that are logged-in and belong to different tenant will not be able to access the edge.", + "However, users that are logged-in and belong to different tenant will not be able to access the edge." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST) @@ -355,7 +356,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Tenant Edges (getTenantEdges)", notes = "Returns a page of edges owned by tenant. " + - PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -387,7 +388,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Tenant Edge Infos (getTenantEdgeInfos)", notes = "Returns a page of edges info objects owned by tenant. " + - PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION, + PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @@ -420,7 +421,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Tenant Edge (getTenantEdge)", notes = "Requested edge must be owned by tenant or customer that the user belongs to. " + - "Edge name is an unique property of edge. So it can be used to identify the edge.", + "Edge name is an unique property of edge. So it can be used to identify the edge." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET) @@ -437,7 +438,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Set root rule chain for provided edge (setRootRuleChain)", notes = "Change root rule chain of the edge to the new provided rule chain. \n" + - "This operation will send a notification to update root rule chain on remote edge service.", + "This operation will send a notification to update root rule chain on remote edge service." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST) @@ -475,7 +476,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Customer Edges (getCustomerEdges)", notes = "Returns a page of edges objects assigned to customer. " + - PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE) + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -520,7 +521,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Get Customer Edge Infos (getCustomerEdgeInfos)", notes = "Returns a page of edges info objects assigned to customer. " + - PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION, produces = MediaType.APPLICATION_JSON_VALUE) + PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/customer/{customerId}/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -564,7 +565,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Get Edges By Ids (getEdgesByIds)", - notes = "Requested edges must be owned by tenant or assigned to customer which user is performing the request.", + notes = "Requested edges must be owned by tenant or assigned to customer which user is performing the request." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) @@ -602,7 +603,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Find related edges (findByQuery)", notes = "Returns all edges that are related to the specific entity. " + "The entity id, relation type, edge types, depth of the search, and other query parameters defined using complex 'EdgeSearchQuery' object. " + - "See 'Model' tab of the Parameters for more info.", + "See 'Model' tab of the Parameters for more info." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges", method = RequestMethod.POST) @@ -636,7 +637,8 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Get Edge Types (getEdgeTypes)", - notes = "Returns a set of unique edge types based on edges that are either owned by the tenant or assigned to the customer which user is performing the request.", + notes = "Returns a set of unique edge types based on edges that are either owned by the tenant or assigned to the customer which user is performing the request." + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/types", method = RequestMethod.GET) @@ -654,7 +656,7 @@ public class EdgeController extends BaseController { @ApiOperation(value = "Sync edge (syncEdge)", notes = "Starts synchronization process between edge and cloud. \n" + - "All entities that are assigned to particular edge are going to be send to remote edge service.") + "All entities that are assigned to particular edge are going to be send to remote edge service." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/sync/{edgeId}", method = RequestMethod.POST) public void syncEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @@ -676,7 +678,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Find missing rule chains (findMissingToRelatedRuleChains)", - notes = "Returns list of rule chains ids that are not assigned to particular edge, but these rule chains are present in the already assigned rule chains to edge.") + notes = "Returns list of rule chains ids that are not assigned to particular edge, but these rule chains are present in the already assigned rule chains to edge." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/missingToRelatedRuleChains/{edgeId}", method = RequestMethod.GET) @ResponseBody @@ -694,7 +696,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Import the bulk of edges (processEdgesBulkImport)", - notes = "There's an ability to import the bulk of edges using the only .csv file.", + notes = "There's an ability to import the bulk of edges using the only .csv file." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PostMapping("/edge/bulk_import") diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 8be2196ff6..509da8bc73 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -497,7 +497,7 @@ public class EntityQueryController extends BaseController { "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + ENTITY_FILTERS + KEY_FILTERS + - TENANT_OR_USER_AUTHORITY_PARAGRAPH;; + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;; private static final String ENTITY_DATA_QUERY_DESCRIPTION = "Allows to run complex queries over platform entities (devices, assets, customers, etc) " + @@ -580,7 +580,7 @@ public class EntityQueryController extends BaseController { "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + ENTITY_FILTERS + KEY_FILTERS + - TENANT_OR_USER_AUTHORITY_PARAGRAPH; + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; private static final String ALARM_DATA_QUERY_DESCRIPTION = "This method description defines how Alarm Data Query extends the Entity Data Query. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java index 9b9cadfd6c..072d4125b4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java +++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java @@ -45,7 +45,7 @@ public class OAuth2ConfigTemplateController extends BaseController { private static final String OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION = "Client registration template is OAuth2 provider configuration template with default settings for registering new OAuth2 clients"; - @ApiOperation(value = "Create or update OAuth2 client registration template (saveClientRegistrationTemplate)", + @ApiOperation(value = "Create or update OAuth2 client registration template (saveClientRegistrationTemplate)" + SYSTEM_AUTHORITY_PARAGRAPH, notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(method = RequestMethod.POST) @@ -59,7 +59,7 @@ public class OAuth2ConfigTemplateController extends BaseController { } } - @ApiOperation(value = "Delete OAuth2 client registration template by id (deleteClientRegistrationTemplate)", + @ApiOperation(value = "Delete OAuth2 client registration template by id (deleteClientRegistrationTemplate)" + SYSTEM_AUTHORITY_PARAGRAPH, notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/{clientRegistrationTemplateId}", method = RequestMethod.DELETE) @@ -76,7 +76,7 @@ public class OAuth2ConfigTemplateController extends BaseController { } } - @ApiOperation(value = "Get the list of all OAuth2 client registration templates (getClientRegistrationTemplates)", + @ApiOperation(value = "Get the list of all OAuth2 client registration templates (getClientRegistrationTemplates)" + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH, notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(method = RequestMethod.GET, produces = "application/json") diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java index bfa29d0ceb..3513cb3139 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java @@ -88,7 +88,7 @@ public class OAuth2Controller extends BaseController { } } - @ApiOperation(value = "Get current OAuth2 settings (getCurrentOAuth2Info)") + @ApiOperation(value = "Get current OAuth2 settings (getCurrentOAuth2Info)", notes = SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/oauth2/config", method = RequestMethod.GET, produces = "application/json") @ResponseBody @@ -101,7 +101,7 @@ public class OAuth2Controller extends BaseController { } } - @ApiOperation(value = "Save OAuth2 settings (saveOAuth2Info)") + @ApiOperation(value = "Save OAuth2 settings (saveOAuth2Info)", notes = SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/oauth2/config", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @@ -118,7 +118,7 @@ public class OAuth2Controller extends BaseController { @ApiOperation(value = "Get OAuth2 log in processing URL (getLoginProcessingUrl)", notes = "Returns the URL enclosed in " + "double quotes. After successful authentication with OAuth2 provider, it makes a redirect to this path so that the platform can do " + "further log in processing. This URL may be configured as 'security.oauth2.loginProcessingUrl' property in yml configuration file, or " + - "as 'SECURITY_OAUTH2_LOGIN_PROCESSING_URL' env variable. By default it is '/login/oauth2/code/'") + "as 'SECURITY_OAUTH2_LOGIN_PROCESSING_URL' env variable. By default it is '/login/oauth2/code/'" + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @RequestMapping(value = "/oauth2/loginProcessingUrl", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java index 6f23f461b7..dc8369330a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java @@ -40,7 +40,7 @@ import java.util.UUID; @Slf4j public class RpcV1Controller extends AbstractRpcController { - @ApiOperation(value = "Send one-way RPC request (handleOneWayDeviceRPCRequest)", notes = "Deprecated. See 'Rpc V 2 Controller' instead.") + @ApiOperation(value = "Send one-way RPC request (handleOneWayDeviceRPCRequest)", notes = "Deprecated. See 'Rpc V 2 Controller' instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) @ResponseBody @@ -52,7 +52,7 @@ public class RpcV1Controller extends AbstractRpcController { return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT); } - @ApiOperation(value = "Send two-way RPC request (handleTwoWayDeviceRPCRequest)", notes = "Deprecated. See 'Rpc V 2 Controller' instead.") + @ApiOperation(value = "Send two-way RPC request (handleTwoWayDeviceRPCRequest)", notes = "Deprecated. See 'Rpc V 2 Controller' instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index fa2d4b5ae7..5d8f342e3f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -91,9 +91,9 @@ public class RpcV2Controller extends AbstractRpcController { "In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " + "the result of this call is the response from device, or 504 Gateway Timeout if device is offline."; - private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT + TENANT_OR_USER_AUTHORITY_PARAGRAPH; + private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; - private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_OR_USER_AUTHORITY_PARAGRAPH; + private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; @ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION) @ApiResponses(value = { @@ -131,7 +131,7 @@ public class RpcV2Controller extends AbstractRpcController { return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); } - @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call." + TENANT_OR_USER_AUTHORITY_PARAGRAPH) + @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET) @ResponseBody @@ -147,7 +147,7 @@ public class RpcV2Controller extends AbstractRpcController { } } - @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_OR_USER_AUTHORITY_PARAGRAPH) + @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 1f47b5e059..310c9f9216 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -169,7 +169,7 @@ public class RuleChainController extends BaseController { "The newly created Rule Chain Id will be present in the response. " + "Specify existing Rule Chain id to update the rule chain. " + "Referencing non-existing rule chain Id will cause 'Not Found' error." + - "\n\n" + RULE_CHAIN_DESCRIPTION) + "\n\n" + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain", method = RequestMethod.POST) @ResponseBody @@ -327,7 +327,7 @@ public class RuleChainController extends BaseController { @ApiOperation(value = "Get Rule Chains (getRuleChains)", - notes = "Returns a page of Rule Chains owned by tenant. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS) + notes = "Returns a page of Rule Chains owned by tenant. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody @@ -358,7 +358,8 @@ public class RuleChainController extends BaseController { } @ApiOperation(value = "Delete rule chain (deleteRuleChain)", - notes = "Deletes the rule chain. Referencing non-existing rule chain Id will cause an error. Referencing rule chain that is used in the device profiles will cause an error.") + notes = "Deletes the rule chain. Referencing non-existing rule chain Id will cause an error. " + + "Referencing rule chain that is used in the device profiles will cause an error." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -409,7 +410,7 @@ public class RuleChainController extends BaseController { @ApiOperation(value = "Get latest input message (getLatestRuleNodeDebugInput)", notes = "Gets the input message from the debug events for specified Rule Chain Id. " + - "Referencing non-existing rule chain Id will cause an error. ") + "Referencing non-existing rule chain Id will cause an error. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleNode/{ruleNodeId}/debugIn", method = RequestMethod.GET) @ResponseBody @@ -582,7 +583,7 @@ public class RuleChainController extends BaseController { "Second, remote edge service will receive a copy of assignment rule chain " + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + "Third, once rule chain will be delivered to edge service, it's going to start processing messages locally. " + - "\n\nOnly rule chain with type 'EDGE' can be assigned to edge.", + "\n\nOnly rule chain with type 'EDGE' can be assigned to edge." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.POST) @@ -622,7 +623,7 @@ public class RuleChainController extends BaseController { EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive an 'unassign' command to remove rule chain " + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + - "Third, once 'unassign' command will be delivered to edge service, it's going to remove rule chain locally.", + "Third, once 'unassign' command will be delivered to edge service, it's going to remove rule chain locally." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.DELETE) 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 1c480537c2..3d6eb09807 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -182,7 +182,8 @@ public class TelemetryController extends BaseController { @ApiOperation(value = "Get all attribute keys (getAttributeKeys)", notes = "Returns a list of all attribute key names for the selected entity. " + "In the case of device entity specified, a response will include merged attribute key names list from each scope: " + - "SERVER_SCOPE, CLIENT_SCOPE, SHARED_SCOPE. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + "SERVER_SCOPE, CLIENT_SCOPE, SHARED_SCOPE. " + + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes", method = RequestMethod.GET) @@ -195,7 +196,8 @@ public class TelemetryController extends BaseController { @ApiOperation(value = "Get all attributes keys by scope (getAttributeKeysByScope)", notes = "Returns a list of attribute key names from the specified attributes scope for the selected entity. " + - "If scope parameter is omitted, Get all attribute keys(getAttributeKeys) API will be called. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + "If scope parameter is omitted, Get all attribute keys(getAttributeKeys) API will be called. " + + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}", method = RequestMethod.GET) @@ -210,7 +212,7 @@ public class TelemetryController extends BaseController { @ApiOperation(value = "Get attributes (getAttributes)", notes = GET_ALL_ATTRIBUTES_BASE_DESCRIPTION + " If 'keys' parameter is omitted, AttributeData class objects will be added to the response for all existing keys of the selected entity. " + - INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes", method = RequestMethod.GET) @@ -228,7 +230,7 @@ public class TelemetryController extends BaseController { notes = GET_ALL_ATTRIBUTES_BY_SCOPE_BASE_DESCRIPTION + " In case that 'keys' parameter is not selected, " + "AttributeData class objects will be added to the response for all existing attribute keys from the " + "specified attributes scope of the selected entity. If 'scope' parameter is omitted, " + - "Get attributes (getAttributes) API will be called. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + "Get attributes (getAttributes) API will be called. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/attributes/{scope}", method = RequestMethod.GET) @@ -245,7 +247,7 @@ public class TelemetryController extends BaseController { @ApiOperation(value = "Get timeseries keys (getTimeseriesKeys)", notes = "Returns a list of all telemetry key names for the selected entity based on entity id and entity type specified. " + - INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/keys/timeseries", method = RequestMethod.GET) @@ -259,7 +261,8 @@ public class TelemetryController extends BaseController { @ApiOperation(value = "Get latest timeseries (getLatestTimeseries)", notes = "Returns a JSON structure that represents a Map, where the map key is a telemetry key name " + - "and map value - is a singleton list of TsData class objects. " + TS_DATA_CLASS_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + "and map value - is a singleton list of TsData class objects. " + + TS_DATA_CLASS_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET) @@ -280,7 +283,8 @@ public class TelemetryController extends BaseController { "and map value - is a list of TsData class objects. " + TS_DATA_CLASS_DESCRIPTION + "This method allows us to group original data into intervals and aggregate it using one of the aggregation methods or just limit the number of TsData objects to fetch for each key specified. " + "See the desription of the request parameters for more details. " + - "The result can also be sorted in ascending or descending order. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + "The result can also be sorted in ascending or descending order. " + + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"}) @@ -321,7 +325,7 @@ public class TelemetryController extends BaseController { notes = "Creates or updates the device attributes based on device id, specified attribute scope, " + "and request payload that represents a JSON object with key-value format of attributes to create or update. " + "For example, '{\"temperature\": 26}'. Key is a unique parameter and cannot be overwritten. Only value can " + - "be overwritten for the key. ", + "be overwritten for the key. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK + @@ -344,7 +348,7 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Save or update attributes (saveEntityAttributesV1)", - notes = SAVE_ENTITY_ATTRIBUTES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + notes = SAVE_ENTITY_ATTRIBUTES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK), @@ -365,7 +369,7 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Save or update attributes (saveEntityAttributesV2)", - notes = SAVE_ENTITY_ATTRIBUTES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + notes = SAVE_ENTITY_ATTRIBUTES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK), @@ -386,7 +390,7 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Save or update telemetry (saveEntityTelemetry)", - notes = SAVE_ENTITY_TIMESERIES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + notes = SAVE_ENTITY_TIMESERIES_DESCRIPTION + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @ApiResponse(code = 200, message = SAVE_ENTITY_TIMESERIES_STATUS_OK), @@ -407,7 +411,8 @@ public class TelemetryController extends BaseController { } @ApiOperation(value = "Save or update telemetry with TTL (saveEntityTelemetryWithTTL)", - notes = SAVE_ENTITY_TIMESERIES_DESCRIPTION + "The ttl parameter used only in case of Cassandra DB use for timeseries data storage. " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + notes = SAVE_ENTITY_TIMESERIES_DESCRIPTION + "The ttl parameter used only in case of Cassandra DB use for timeseries data storage. " + + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @ApiResponse(code = 200, message = SAVE_ENTITY_TIMESERIES_STATUS_OK), @@ -431,7 +436,7 @@ public class TelemetryController extends BaseController { @ApiOperation(value = "Delete entity timeseries (deleteEntityTimeseries)", notes = "Delete timeseries for selected entity based on entity id, entity type, keys " + "and removal time range. To delete all data for keys parameter 'deleteAllDataForKeys' should be set to true, " + - "otherwise, will be deleted data that is in range of the selected time interval. ", + "otherwise, will be deleted data that is in range of the selected time interval. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @ApiResponse(code = 200, message = "Timeseries for the selected keys in the request was removed. " + @@ -506,7 +511,7 @@ public class TelemetryController extends BaseController { @ApiOperation(value = "Delete device attributes (deleteEntityAttributes)", notes = "Delete device attributes from the specified attributes scope based on device id and a list of keys to delete. " + - "Selected keys will be deleted only if there are exist in the specified attribute scope. Referencing a non-existing device Id will cause an error", + "Selected keys will be deleted only if there are exist in the specified attribute scope. Referencing a non-existing device Id will cause an error" + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @ApiResponse(code = 200, message = "Device attributes was removed for the selected keys in the request. " + @@ -529,7 +534,7 @@ public class TelemetryController extends BaseController { @ApiOperation(value = "Delete entity attributes (deleteEntityAttributes)", notes = "Delete entity attributes from the specified attributes scope based on entity id, entity type and a list of keys to delete. " + - "Selected keys will be deleted only if there are exist in the specified attribute scope." + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION, + "Selected keys will be deleted only if there are exist in the specified attribute scope." + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @ApiResponse(code = 200, message = "Entity attributes was removed for the selected keys in the request. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index f2362acb7f..4222e76658 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -302,7 +302,7 @@ public class UserController extends BaseController { @ApiOperation(value = "Get Users (getUsers)", notes = "Returns a page of users owned by tenant or customer. The scope depends on authority of the user that performs the request." + - PAGE_DATA_PARAMETERS + TENANT_OR_USER_AUTHORITY_PARAGRAPH) + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/users", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody From bf068011e0fcf416d473f18d80a32ade205d83f0 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 20 Oct 2021 14:58:51 +0300 Subject: [PATCH 099/303] Widget Bundle Controller --- .../server/controller/BaseController.java | 6 ++ .../controller/WidgetsBundleController.java | 35 +++++++++- .../common/data/widget/WidgetsBundle.java | 67 ++++++++++--------- 3 files changed, 74 insertions(+), 34 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 82dc85e978..75638598a2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -179,12 +179,14 @@ public abstract class BaseController { public static final String ENTITY_ID_PARAM_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority."; protected static final String TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; protected static final String CUSTOMER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'CUSTOMER_USER' authority."; + protected static final String AVAILABLE_FOR_ANY_AUTHORIZED_USER = "\n\nAvailable for any authorized user. "; protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; @@ -195,6 +197,8 @@ public abstract class BaseController { protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; + protected static final String WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the widget bundle title."; + protected static final String WIDGET_TYPE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the widget type title."; protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; protected static final String USER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the user email."; @@ -222,6 +226,8 @@ public abstract class BaseController { protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root"; + protected static final String WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, tenantId"; + protected static final String WIDGET_TYPE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, alias, bundleAlias, name"; protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index 14c5d6a860..7ab494f1dc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -44,10 +46,16 @@ import java.util.List; @RequestMapping("/api") public class WidgetsBundleController extends BaseController { + private static final String WIDGET_BUNDLE_DESCRIPTION = "Widget Bundle represents a group(bundle) of widgets. Widgets are grouped into bundle by type or use case. "; + + @ApiOperation(value = "Get Widget Bundle (getWidgetsBundleById)", + notes = "Get the Widget Bundle based on the provided Widget Bundle Id. " + WIDGET_BUNDLE_DESCRIPTION + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.GET) @ResponseBody - public WidgetsBundle getWidgetsBundleById(@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { + public WidgetsBundle getWidgetsBundleById( + @ApiParam(value = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION) + @PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { checkParameter("widgetsBundleId", strWidgetsBundleId); try { WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); @@ -57,10 +65,21 @@ public class WidgetsBundleController extends BaseController { } } + @ApiOperation(value = "Create Or Update Widget Bundle (saveWidgetsBundle)", + notes = "Create or update the Widget Bundle. " + WIDGET_BUNDLE_DESCRIPTION + " " + + "When creating the bundle, platform generates Widget Bundle Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created Widget Bundle Id will be present in the response. " + + "Specify existing Widget Bundle id to update the Widget Bundle. " + + "Referencing non-existing Widget Bundle Id will cause 'Not Found' error." + + "\n\nWidget Bundle alias is unique in the scope of tenant. " + + "Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create bundle request is sent by user with 'SYS_ADMIN' authority." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST) @ResponseBody - public WidgetsBundle saveWidgetsBundle(@RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException { + public WidgetsBundle saveWidgetsBundle( + @ApiParam(value = "A JSON value representing the Widget Bundle.") + @RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException { try { if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { widgetsBundle.setTenantId(TenantId.SYS_TENANT_ID); @@ -80,6 +99,8 @@ public class WidgetsBundleController extends BaseController { } } + @ApiOperation(value = "Delete widgets bundle (deleteWidgetsBundle)", + notes = "Deletes the widget bundle. Referencing non-existing Widget Bundle Id will cause an error." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -97,14 +118,22 @@ public class WidgetsBundleController extends BaseController { } } + @ApiOperation(value = "Get Widget Bundles (getWidgetsBundles)", + notes = "Returns a page of Widget Bundle objects available for current user. " + WIDGET_BUNDLE_DESCRIPTION + " " + + PAGE_DATA_PARAMETERS + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/widgetsBundles", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getWidgetsBundles( + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); @@ -119,6 +148,8 @@ public class WidgetsBundleController extends BaseController { } } + @ApiOperation(value = "Get all Widget Bundles (getWidgetsBundles)", + notes = "Returns an array of Widget Bundle objects that are available for current user." + WIDGET_BUNDLE_DESCRIPTION + " " + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/widgetsBundles", method = RequestMethod.GET) @ResponseBody diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java index 5ef6ff260a..17455d1e38 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java @@ -15,6 +15,10 @@ */ package org.thingsboard.server.common.data.widget; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.TenantId; @@ -23,17 +27,37 @@ import org.thingsboard.server.common.data.validation.NoXss; import java.util.Arrays; +@ApiModel public class WidgetsBundle extends SearchTextBased implements HasTenantId { private static final long serialVersionUID = -7627368878362410489L; + @Getter + @Setter + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", readOnly = true) private TenantId tenantId; + @NoXss + @Getter + @Setter + @ApiModelProperty(position = 4, value = "Unique alias that is used in widget types as a reference widget bundle", readOnly = true) private String alias; + @NoXss + @Getter + @Setter + @ApiModelProperty(position = 5, value = "Title used in search and UI", readOnly = true) private String title; + + @Getter + @Setter + @ApiModelProperty(position = 6, value = "Base64 encoded thumbnail", readOnly = true) private String image; + @NoXss + @Getter + @Setter + @ApiModelProperty(position = 7, value = "Description", readOnly = true) private String description; public WidgetsBundle() { @@ -53,42 +77,21 @@ public class WidgetsBundle extends SearchTextBased implements H this.description = widgetsBundle.getDescription(); } - public TenantId getTenantId() { - return tenantId; - } - - public void setTenantId(TenantId tenantId) { - this.tenantId = tenantId; - } - - public String getAlias() { - return alias; - } - - public void setAlias(String alias) { - this.alias = alias; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getImage() { - return image; + @ApiModelProperty(position = 1, value = "JSON object with the Widget Bundle Id. " + + "Specify this field to update the Widget Bundle. " + + "Referencing non-existing Widget Bundle Id will cause error. " + + "Omit this field to create new Widget Bundle." ) + @Override + public WidgetsBundleId getId() { + return super.getId(); } - public void setImage(String image) { - this.image = image; + @ApiModelProperty(position = 2, value = "Timestamp of the Widget Bundle creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); } - public String getDescription() { return description; } - - public void setDescription(String description) { this.description = description; } - @Override public String getSearchText() { return getTitle(); From 96cdae876409274e211a6e2b79dc38996379ed42 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 20 Oct 2021 15:26:42 +0300 Subject: [PATCH 100/303] Widget Type description --- .../server/controller/BaseController.java | 4 +- .../controller/WidgetTypeController.java | 50 +++++++++++++++++-- .../controller/WidgetsBundleController.java | 8 +-- .../common/data/widget/BaseWidgetType.java | 20 ++++++++ .../server/common/data/widget/WidgetType.java | 2 + .../common/data/widget/WidgetTypeDetails.java | 3 ++ .../common/data/widget/WidgetTypeInfo.java | 4 ++ 7 files changed, 83 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 75638598a2..75adfffa61 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -180,6 +180,8 @@ public abstract class BaseController { public static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String WIDGET_TYPE_ID_PARAM_DESCRIPTION = "A string value representing the widget type id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; @@ -198,7 +200,6 @@ public abstract class BaseController { protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; protected static final String WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the widget bundle title."; - protected static final String WIDGET_TYPE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the widget type title."; protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; protected static final String USER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the user email."; @@ -227,7 +228,6 @@ public abstract class BaseController { protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root"; protected static final String WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, tenantId"; - protected static final String WIDGET_TYPE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, alias, bundleAlias, name"; protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index ad81821a82..a19799444b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -48,10 +50,20 @@ import java.util.List; @RequestMapping("/api") public class WidgetTypeController extends BaseController { + private static final String WIDGET_TYPE_DESCRIPTION = "Widget Type represents the template for widget creation. Widget Type and Widget are similar to class and object in OOP theory."; + private static final String WIDGET_TYPE_DETAILS_DESCRIPTION = "Widget Type Details extend Widget Type and add image and description properties. " + + "Those properties are useful to edit the Widget Type but they are not required for Dashboard rendering. "; + private static final String WIDGET_TYPE_INFO_DESCRIPTION = "Widget Type Info is a lightweight object that represents Widget Type but does not contain the heavyweight widget descriptor JSON"; + + + @ApiOperation(value = "Get Widget Type Details (getWidgetTypeById)", + notes = "Get the Widget Type Details based on the provided Widget Type Id. " + WIDGET_TYPE_DETAILS_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetType/{widgetTypeId}", method = RequestMethod.GET) @ResponseBody - public WidgetTypeDetails getWidgetTypeById(@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { + public WidgetTypeDetails getWidgetTypeById( + @ApiParam(value = WIDGET_TYPE_ID_PARAM_DESCRIPTION, required = true) + @PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { checkParameter("widgetTypeId", strWidgetTypeId); try { WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); @@ -61,10 +73,21 @@ public class WidgetTypeController extends BaseController { } } + @ApiOperation(value = "Create Or Update Widget Type (saveWidgetType)", + notes = "Create or update the Widget Type. " + WIDGET_TYPE_DESCRIPTION + " " + + "When creating the Widget Type, platform generates Widget Type Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created Widget Type Id will be present in the response. " + + "Specify existing Widget Type id to update the Widget Type. " + + "Referencing non-existing Widget Type Id will cause 'Not Found' error." + + "\n\nWidget Type alias is unique in the scope of Widget Bundle. " + + "Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create request is sent by user with 'SYS_ADMIN' authority." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetType", method = RequestMethod.POST) @ResponseBody - public WidgetTypeDetails saveWidgetType(@RequestBody WidgetTypeDetails widgetTypeDetails) throws ThingsboardException { + public WidgetTypeDetails saveWidgetType( + @ApiParam(value = "A JSON value representing the Widget Type Details.", required = true) + @RequestBody WidgetTypeDetails widgetTypeDetails) throws ThingsboardException { try { if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { widgetTypeDetails.setTenantId(TenantId.SYS_TENANT_ID); @@ -84,10 +107,14 @@ public class WidgetTypeController extends BaseController { } } + @ApiOperation(value = "Delete widget type (deleteWidgetType)", + notes = "Deletes the Widget Type. Referencing non-existing Widget Type Id will cause an error." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetType/{widgetTypeId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteWidgetType(@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { + public void deleteWidgetType( + @ApiParam(value = WIDGET_TYPE_ID_PARAM_DESCRIPTION, required = true) + @PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { checkParameter("widgetTypeId", strWidgetTypeId); try { WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); @@ -101,11 +128,15 @@ public class WidgetTypeController extends BaseController { } } + @ApiOperation(value = "Get all Widget types for specified Bundle (getBundleWidgetTypes)", + notes = "Returns an array of Widget Type objects that belong to specified Widget Bundle." + WIDGET_TYPE_DESCRIPTION + " " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetTypes", params = {"isSystem", "bundleAlias"}, method = RequestMethod.GET) @ResponseBody public List getBundleWidgetTypes( + @ApiParam(value = "System or Tenant", required = true) @RequestParam boolean isSystem, + @ApiParam(value = "Widget Bundle alias", required = true) @RequestParam String bundleAlias) throws ThingsboardException { try { TenantId tenantId; @@ -120,11 +151,15 @@ public class WidgetTypeController extends BaseController { } } + @ApiOperation(value = "Get all Widget types details for specified Bundle (getBundleWidgetTypes)", + notes = "Returns an array of Widget Type Details objects that belong to specified Widget Bundle." + WIDGET_TYPE_DETAILS_DESCRIPTION + " " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetTypesDetails", params = {"isSystem", "bundleAlias"}, method = RequestMethod.GET) @ResponseBody public List getBundleWidgetTypesDetails( + @ApiParam(value = "System or Tenant", required = true) @RequestParam boolean isSystem, + @ApiParam(value = "Widget Bundle alias", required = true) @RequestParam String bundleAlias) throws ThingsboardException { try { TenantId tenantId; @@ -139,11 +174,15 @@ public class WidgetTypeController extends BaseController { } } + @ApiOperation(value = "Get Widget Type Info objects (getBundleWidgetTypesInfos)", + notes = "Get the Widget Type Info objects based on the provided parameters. " + WIDGET_TYPE_INFO_DESCRIPTION + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetTypesInfos", params = {"isSystem", "bundleAlias"}, method = RequestMethod.GET) @ResponseBody public List getBundleWidgetTypesInfos( + @ApiParam(value = "System or Tenant", required = true) @RequestParam boolean isSystem, + @ApiParam(value = "Widget Bundle alias", required = true) @RequestParam String bundleAlias) throws ThingsboardException { try { TenantId tenantId; @@ -158,12 +197,17 @@ public class WidgetTypeController extends BaseController { } } + @ApiOperation(value = "Get Widget Type (getWidgetType)", + notes = "Get the Widget Type based on the provided parameters. " + WIDGET_TYPE_DESCRIPTION + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/widgetType", params = {"isSystem", "bundleAlias", "alias"}, method = RequestMethod.GET) @ResponseBody public WidgetType getWidgetType( + @ApiParam(value = "System or Tenant", required = true) @RequestParam boolean isSystem, + @ApiParam(value = "Widget Bundle alias", required = true) @RequestParam String bundleAlias, + @ApiParam(value = "Widget Type alias", required = true) @RequestParam String alias) throws ThingsboardException { try { TenantId tenantId; diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index 7ab494f1dc..08bd3e3984 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -54,7 +54,7 @@ public class WidgetsBundleController extends BaseController { @RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.GET) @ResponseBody public WidgetsBundle getWidgetsBundleById( - @ApiParam(value = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION) + @ApiParam(value = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { checkParameter("widgetsBundleId", strWidgetsBundleId); try { @@ -78,7 +78,7 @@ public class WidgetsBundleController extends BaseController { @RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST) @ResponseBody public WidgetsBundle saveWidgetsBundle( - @ApiParam(value = "A JSON value representing the Widget Bundle.") + @ApiParam(value = "A JSON value representing the Widget Bundle.", required = true) @RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException { try { if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { @@ -104,7 +104,9 @@ public class WidgetsBundleController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void deleteWidgetsBundle(@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { + public void deleteWidgetsBundle( + @ApiParam(value = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION, required = true) + @PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { checkParameter("widgetsBundleId", strWidgetsBundleId); try { WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java index 300015fa23..0cc3e63b05 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.widget; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.HasTenantId; @@ -27,12 +28,16 @@ public class BaseWidgetType extends BaseData implements HasTenantI private static final long serialVersionUID = 8388684344603660756L; + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", readOnly = true) private TenantId tenantId; @NoXss + @ApiModelProperty(position = 4, value = "Reference to widget bundle", readOnly = true) private String bundleAlias; @NoXss + @ApiModelProperty(position = 5, value = "Unique alias that is used in dashboards as a reference widget type", readOnly = true) private String alias; @NoXss + @ApiModelProperty(position = 6, value = "Widget name used in search and UI", readOnly = true) private String name; public BaseWidgetType() { @@ -50,4 +55,19 @@ public class BaseWidgetType extends BaseData implements HasTenantI this.alias = widgetType.getAlias(); this.name = widgetType.getName(); } + + @ApiModelProperty(position = 1, value = "JSON object with the Widget Type Id. " + + "Specify this field to update the Widget Type. " + + "Referencing non-existing Widget Type Id will cause error. " + + "Omit this field to create new Widget Type." ) + @Override + public WidgetTypeId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the Widget Type creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java index 04432093ea..b2c5e5b3c2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java @@ -16,12 +16,14 @@ package org.thingsboard.server.common.data.widget; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.WidgetTypeId; @Data public class WidgetType extends BaseWidgetType { + @ApiModelProperty(position = 7, value = "Complex JSON object that describes the widget type", readOnly = true) private transient JsonNode descriptor; public WidgetType() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java index 00d7390ab7..fe7f87c7af 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java @@ -16,6 +16,7 @@ package org.thingsboard.server.common.data.widget; import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.validation.NoXss; @@ -24,8 +25,10 @@ import org.thingsboard.server.common.data.validation.NoXss; @JsonPropertyOrder({ "alias", "name", "image", "description", "descriptor" }) public class WidgetTypeDetails extends WidgetType { + @ApiModelProperty(position = 8, value = "Base64 encoded thumbnail", readOnly = true) private String image; @NoXss + @ApiModelProperty(position = 9, value = "Description of the widget", readOnly = true) private String description; public WidgetTypeDetails() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeInfo.java index 2fde13552b..2898a05c13 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeInfo.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.widget; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.validation.NoXss; @@ -22,10 +23,13 @@ import org.thingsboard.server.common.data.validation.NoXss; @Data public class WidgetTypeInfo extends BaseWidgetType { + @ApiModelProperty(position = 7, value = "Base64 encoded widget thumbnail", readOnly = true) private String image; @NoXss + @ApiModelProperty(position = 7, value = "Description of the widget type", readOnly = true) private String description; @NoXss + @ApiModelProperty(position = 8, value = "Type of the widget (timeseries, latest, control, alarm or static)", readOnly = true) private String widgetType; public WidgetTypeInfo() { From 85b1cd0401e5de381af0188b842215fc83bb566a Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Wed, 20 Oct 2021 15:31:33 +0300 Subject: [PATCH 101/303] added description to device profile controller --- .../server/controller/BaseController.java | 129 +++-- .../controller/DeviceProfileController.java | 464 +++++++++++++++++- .../controller/EntityQueryController.java | 119 +++-- 3 files changed, 605 insertions(+), 107 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index cd0109d72a..121c51cd4d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -155,6 +155,8 @@ public abstract class BaseController { /*Swagger UI description*/ + protected static final String NEW_LINE = "\n\n"; + public static final String CUSTOMER_ID = "customerId"; public static final String TENANT_ID = "tenantId"; public static final String DEVICE_ID = "deviceId"; @@ -239,7 +241,7 @@ public abstract class BaseController { protected static final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; protected static final String EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Unassignment works in async way - first, 'unassign' notification event pushed to edge queue on platform. "; - protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)" ; + protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; protected static final String EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Assignment works in async way - first, notification event pushed to edge service queue on platform. "; protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; @@ -257,41 +259,112 @@ public abstract class BaseController { protected static final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; protected static final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_CREATE_RULES_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{ \"createRules\": { \"MAJOR\": { \"schedule\": null, \"condition\": { \"spec\": { \"type\": \"SIMPLE\" }, " + - "\"condition\": [{ \"key\": { \"key\": \"temp\", \"type\": \"TIME_SERIES\" }, \"value\": null, \"predicate\": { \"type\": \"NUMERIC\", \"value\": { \"userValue\": null, \"defaultValue\": 30.0, \"dynamicValue\": null }, " + - "\"operation\": \"GREATER\" }, \"valueType\": \"NUMERIC\" }] }, \"dashboardId\": null, \"alarmDetails\": null }, \"CRITICAL\": { \"schedule\": null, \"condition\": { \"spec\": { \"type\": \"SIMPLE\" }, \"condition\": " + - "[{ \"key\": { \"key\": \"temp\", \"type\": \"TIME_SERIES\" }, \"value\": null, \"predicate\": { \"type\": \"NUMERIC\", \"value\": { \"userValue\": null, \"defaultValue\": 50.0, \"dynamicValue\": null }, \"operation\": \"GREATER\" }, " + - "\"valueType\": \"NUMERIC\" }] }, \"dashboardId\": null, \"alarmDetails\": null } } }" + MARKDOWN_CODE_BLOCK_END; + protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + + "Provides a hint about the data type of the entity field that is defined in the filter key. " + + "The value type impacts the list of possible operations that you may use in the corresponding predicate. For example, you may use 'STARTS_WITH' or 'END_WITH', but you can't use 'GREATER_OR_EQUAL' for string values." + + "The following filter value types and corresponding predicate operations are supported: " + NEW_LINE + + " * 'STRING' - used to filter any 'String' or 'JSON' values. Operations: EQUAL, NOT_EQUAL, STARTS_WITH, ENDS_WITH, CONTAINS, NOT_CONTAINS; \n" + + " * 'NUMERIC' - used for 'Long' and 'Double' values. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n" + + " * 'BOOLEAN' - used for boolean values. Operations: EQUAL, NOT_EQUAL;\n" + + " * 'DATE_TIME' - similar to numeric, transforms value to milliseconds since epoch. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n"; protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{ \"schedule\": { \"type\": \"SPECIFIC_TIME\", \"endsOn\": 64800000, \"startsOn\": 43200000, \"timezone\": \"Europe/Kiev\", \"daysOfWeek\": [1, 3, 7] } }" + + "{\n" + + " \"schedule\":{\n" + + " \"type\":\"SPECIFIC_TIME\",\n" + + " \"endsOn\":64800000,\n" + + " \"startsOn\":43200000,\n" + + " \"timezone\":\"Europe/Kiev\",\n" + + " \"daysOfWeek\":[\n" + + " 1,\n" + + " 3,\n" + + " 5\n" + + " ]\n" + + " }\n" + + "}" + MARKDOWN_CODE_BLOCK_END; protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{ \"schedule\": { \"type\": \"CUSTOM\", \"items\": [{ \"endsOn\": 64800000, \"enabled\": true, \"startsOn\": 43200000, \"dayOfWeek\": 1 }, " + - "{ \"endsOn\": 0, \"enabled\": false, \"startsOn\": 0, \"dayOfWeek\": 2 }, { \"endsOn\": 57600000, \"enabled\": true, \"startsOn\": 36000000, \"dayOfWeek\": 3 }, " + - "{ \"endsOn\": 0, \"enabled\": false, \"startsOn\": 0, \"dayOfWeek\": 4 }, { \"endsOn\": 68400000, \"enabled\": true, \"startsOn\": 32400000, \"dayOfWeek\": 5 }, " + - "{ \"endsOn\": 0, \"enabled\": false, \"startsOn\": 0, \"dayOfWeek\": 6 }, { \"endsOn\": 0, \"enabled\": false, \"startsOn\": 0, \"dayOfWeek\": 7 }], \"timezone\": \"Europe/Kiev\" } }" + + "{\n" + + " \"schedule\":{\n" + + " \"type\":\"CUSTOM\",\n" + + " \"items\":[\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":1\n" + + " },\n" + + " {\n" + + " \"endsOn\":64800000,\n" + + " \"enabled\":true,\n" + + " \"startsOn\":43200000,\n" + + " \"dayOfWeek\":2\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":3\n" + + " },\n" + + " {\n" + + " \"endsOn\":57600000,\n" + + " \"enabled\":true,\n" + + " \"startsOn\":36000000,\n" + + " \"dayOfWeek\":4\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":5\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":6\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":7\n" + + " }\n" + + " ],\n" + + " \"timezone\":\"Europe/Kiev\"\n" + + " }\n" + + "}" + MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\"schedule\": null}" + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "\"schedule\": null" + MARKDOWN_CODE_BLOCK_END; protected static final String DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{ \"spec\": { \"type\": \"DURATION\", \"unit\": \"MINUTES\", \"predicate\": { \"userValue\": null, \"defaultValue\": 30, \"dynamicValue\": null } } }" + + "{\n" + + " \"spec\":{\n" + + " \"type\":\"REPEATING\",\n" + + " \"predicate\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":5,\n" + + " \"dynamicValue\":{\n" + + " \"inherit\":true,\n" + + " \"sourceType\":\"CURRENT_DEVICE\",\n" + + " \"sourceAttribute\":\"tempAttr\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}" + MARKDOWN_CODE_BLOCK_END; protected static final String DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{ \"spec\": { \"type\": \"REPEATING\", \"predicate\": { \"userValue\": null, \"defaultValue\": 3, \"dynamicValue\": " + - "{ \"inherit\": false, \"sourceType\": \"CURRENT_DEVICE\", \"sourceAttribute\": \"repeatingLimit\" } } } }" + - MARKDOWN_CODE_BLOCK_END; - - protected static final String DEVICE_PROFILE_CONDITIONS_TIME_SERIES_NUMERIC_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{ \"condition\": [{ \"key\": { \"key\": \"temp\", \"type\": \"TIME_SERIES\" }, " + - "\"value\": null, \"predicate\": { \"type\": \"NUMERIC\", \"value\": { \"userValue\": null, \"defaultValue\": 30.0, \"dynamicValue\": null }, \"operation\": \"GREATER\" }, " + - "\"valueType\": \"NUMERIC\" }] }" + - MARKDOWN_CODE_BLOCK_END; - - protected static final String DEVICE_PROFILE_CONDITIONS_CONSTANT_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{ \"condition\": [{ \"key\": { \"key\": \"constantKey\", \"type\": \"CONSTANT\" }, \"value\": true, \"predicate\": { \"type\": \"BOOLEAN\", \"value\": " + - "{ \"userValue\": null, \"defaultValue\": false, \"dynamicValue\": { \"inherit\": false, \"sourceType\": \"CURRENT_TENANT\", \"sourceAttribute\": \"alarmEnabled\" } }, " + - "\"operation\": \"EQUAL\" }, \"valueType\": \"BOOLEAN\" }] }" + + "{\n" + + " \"spec\":{\n" + + " \"type\":\"DURATION\",\n" + + " \"unit\":\"MINUTES\",\n" + + " \"predicate\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":30,\n" + + " \"dynamicValue\":null\n" + + " }\n" + + " }\n" + + "}" + MARKDOWN_CODE_BLOCK_END; protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; @@ -299,8 +372,6 @@ public abstract class BaseController { protected static final String ADMINISTRATOR_AUTHORITY_ONLY = "Available for users with 'Tenant Administrator' authority only."; - protected static final String NEW_LINE = "\n\n"; - public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; protected static final String HOME_DASHBOARD = "homeDashboardId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 05e62becdb..e3b68a3592 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -55,6 +55,453 @@ import java.util.UUID; @Slf4j public class DeviceProfileController extends BaseController { + private static final String COAP_TRANSPORT_CONFIGURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\":\"COAP\",\n" + + " \"clientSettings\":{\n" + + " \"edrxCycle\":null,\n" + + " \"powerMode\":\"DRX\",\n" + + " \"psmActivityTimer\":null,\n" + + " \"pagingTransmissionWindow\":null\n" + + " },\n" + + " \"coapDeviceTypeConfiguration\":{\n" + + " \"coapDeviceType\":\"DEFAULT\",\n" + + " \"transportPayloadTypeConfiguration\":{\n" + + " \"transportPayloadType\":\"JSON\"\n" + + " }\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + + private static final String TRANSPORT_CONFIGURATION = "# Transport Configuration" + NEW_LINE + + "5 transport configuration types are available:\n" + + " * 'DEFAULT';\n" + + " * 'MQTT';\n" + + " * 'LWM2M';\n" + + " * 'COAP';\n" + + " * 'SNMP'." + NEW_LINE + "Default type supports basic MQTT, HTTP, CoAP and LwM2M transports. " + + "Please refer to the [docs](https://thingsboard.io/docs/user-guide/device-profiles/#transport-configuration) for more details about other types.\n" + + "\nSee another example of COAP transport configuration below:" + NEW_LINE + COAP_TRANSPORT_CONFIGURATION_EXAMPLE; + + private static final String ALARM_FILTER_KEY = "## Alarm Filter Key" + NEW_LINE + + "Filter Key defines either entity field, attribute, telemetry or constant. It is a JSON object that consists the key name and type. The following filter key types are supported:\n" + + " * 'ATTRIBUTE' - used for attributes values;\n" + + " * 'TIME_SERIES' - used for time-series values;\n" + + " * 'ENTITY_FIELD' - used for accessing entity fields like 'name', 'label', etc. The list of available fields depends on the entity type;\n" + + " * 'CONSTANT' - constant value specified." + NEW_LINE + "Let's review the example:" + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + + private static final String FILTER_PREDICATE = NEW_LINE + "## Filter Predicate" + NEW_LINE + + "Filter Predicate defines the logical expression to evaluate. The list of available operations depends on the filter value type, see above. " + + "Platform supports 4 predicate types: 'STRING', 'NUMERIC', 'BOOLEAN' and 'COMPLEX'. The last one allows to combine multiple operations over one filter key." + NEW_LINE + + "Simple predicate example to check 'value < 100': " + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 100,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + NEW_LINE + + "Complex predicate example, to check 'value < 10 or value > 20': " + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"OR\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 10,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 20,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + NEW_LINE + + "More complex predicate example, to check 'value < 10 or (value > 50 && value < 60)': " + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"OR\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 10,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"AND\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 50,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 60,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + NEW_LINE + + "You may also want to replace hardcoded values (for example, temperature > 20) with the more dynamic " + + "expression (for example, temperature > value of the tenant attribute with key 'temperatureThreshold'). " + + "It is possible to use 'dynamicValue' to define attribute of the tenant, customer or device. " + + "See example below:" + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 0,\n" + + " \"dynamicValue\": {\n" + + " \"inherit\": false,\n" + + " \"sourceType\": \"CURRENT_TENANT\",\n" + + " \"sourceAttribute\": \"temperatureThreshold\"\n" + + " }\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + NEW_LINE + + "Note that you may use 'CURRENT_DEVICE', 'CURRENT_CUSTOMER' and 'CURRENT_TENANT' as a 'sourceType'. The 'defaultValue' is used when the attribute with such a name is not defined for the chosen source. " + + "The 'sourceAttribute' can be inherited from the owner of the specified 'sourceType' if 'inherit' is set to true."; + + private static final String KEY_FILTERS_DESCRIPTION = "# Key Filters" + NEW_LINE + + "Key filter objects are created under the **'condition'** array. They allow you to define complex logical expressions over entity field, " + + "attribute, latest time-series value or constant. The filter is defined using 'key', 'valueType', " + + "'value' (refers to the value of the 'CONSTANT' alarm filter key type) and 'predicate' objects. Let's review each object:" + NEW_LINE + + ALARM_FILTER_KEY + FILTER_VALUE_TYPE + NEW_LINE + FILTER_PREDICATE + NEW_LINE; + + private static final String DEFAULT_DEVICE_PROFILE_DATA_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + + " \"alarms\":[\n" + + " ],\n" + + " \"configuration\":{\n" + + " \"type\":\"DEFAULT\"\n" + + " },\n" + + " \"provisionConfiguration\":{\n" + + " \"type\":\"DISABLED\",\n" + + " \"provisionDeviceSecret\":null\n" + + " },\n" + + " \"transportConfiguration\":{\n" + + " \"type\":\"DEFAULT\"\n" + + " }\n" + + "}" + MARKDOWN_CODE_BLOCK_END; + + private static final String CUSTOM_DEVICE_PROFILE_DATA_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + + " \"alarms\":[\n" + + " {\n" + + " \"id\":\"2492b935-1226-59e9-8615-17d8978a4f93\",\n" + + " \"alarmType\":\"Temperature Alarm\",\n" + + " \"clearRule\":{\n" + + " \"schedule\":null,\n" + + " \"condition\":{\n" + + " \"spec\":{\n" + + " \"type\":\"SIMPLE\"\n" + + " },\n" + + " \"condition\":[\n" + + " {\n" + + " \"key\":{\n" + + " \"key\":\"temperature\",\n" + + " \"type\":\"TIME_SERIES\"\n" + + " },\n" + + " \"value\":null,\n" + + " \"predicate\":{\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":30.0,\n" + + " \"dynamicValue\":null\n" + + " },\n" + + " \"operation\":\"LESS\"\n" + + " },\n" + + " \"valueType\":\"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"dashboardId\":null,\n" + + " \"alarmDetails\":null\n" + + " },\n" + + " \"propagate\":false,\n" + + " \"createRules\":{\n" + + " \"MAJOR\":{\n" + + " \"schedule\":{\n" + + " \"type\":\"SPECIFIC_TIME\",\n" + + " \"endsOn\":64800000,\n" + + " \"startsOn\":43200000,\n" + + " \"timezone\":\"Europe/Kiev\",\n" + + " \"daysOfWeek\":[\n" + + " 1,\n" + + " 3,\n" + + " 5\n" + + " ]\n" + + " },\n" + + " \"condition\":{\n" + + " \"spec\":{\n" + + " \"type\":\"DURATION\",\n" + + " \"unit\":\"MINUTES\",\n" + + " \"predicate\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":30,\n" + + " \"dynamicValue\":null\n" + + " }\n" + + " },\n" + + " \"condition\":[\n" + + " {\n" + + " \"key\":{\n" + + " \"key\":\"temperature\",\n" + + " \"type\":\"TIME_SERIES\"\n" + + " },\n" + + " \"value\":null,\n" + + " \"predicate\":{\n" + + " \"type\":\"COMPLEX\",\n" + + " \"operation\":\"OR\",\n" + + " \"predicates\":[\n" + + " {\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":50.0,\n" + + " \"dynamicValue\":null\n" + + " },\n" + + " \"operation\":\"LESS_OR_EQUAL\"\n" + + " },\n" + + " {\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":30.0,\n" + + " \"dynamicValue\":null\n" + + " },\n" + + " \"operation\":\"GREATER\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"valueType\":\"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"dashboardId\":null,\n" + + " \"alarmDetails\":null\n" + + " },\n" + + " \"WARNING\":{\n" + + " \"schedule\":{\n" + + " \"type\":\"CUSTOM\",\n" + + " \"items\":[\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":1\n" + + " },\n" + + " {\n" + + " \"endsOn\":64800000,\n" + + " \"enabled\":true,\n" + + " \"startsOn\":43200000,\n" + + " \"dayOfWeek\":2\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":3\n" + + " },\n" + + " {\n" + + " \"endsOn\":57600000,\n" + + " \"enabled\":true,\n" + + " \"startsOn\":36000000,\n" + + " \"dayOfWeek\":4\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":5\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":6\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":7\n" + + " }\n" + + " ],\n" + + " \"timezone\":\"Europe/Kiev\"\n" + + " },\n" + + " \"condition\":{\n" + + " \"spec\":{\n" + + " \"type\":\"REPEATING\",\n" + + " \"predicate\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":5,\n" + + " \"dynamicValue\":null\n" + + " }\n" + + " },\n" + + " \"condition\":[\n" + + " {\n" + + " \"key\":{\n" + + " \"key\":\"tempConstant\",\n" + + " \"type\":\"CONSTANT\"\n" + + " },\n" + + " \"value\":30,\n" + + " \"predicate\":{\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":0.0,\n" + + " \"dynamicValue\":{\n" + + " \"inherit\":false,\n" + + " \"sourceType\":\"CURRENT_DEVICE\",\n" + + " \"sourceAttribute\":\"tempThreshold\"\n" + + " }\n" + + " },\n" + + " \"operation\":\"EQUAL\"\n" + + " },\n" + + " \"valueType\":\"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"dashboardId\":null,\n" + + " \"alarmDetails\":null\n" + + " },\n" + + " \"CRITICAL\":{\n" + + " \"schedule\":null,\n" + + " \"condition\":{\n" + + " \"spec\":{\n" + + " \"type\":\"SIMPLE\"\n" + + " },\n" + + " \"condition\":[\n" + + " {\n" + + " \"key\":{\n" + + " \"key\":\"temperature\",\n" + + " \"type\":\"TIME_SERIES\"\n" + + " },\n" + + " \"value\":null,\n" + + " \"predicate\":{\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":50.0,\n" + + " \"dynamicValue\":null\n" + + " },\n" + + " \"operation\":\"GREATER\"\n" + + " },\n" + + " \"valueType\":\"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"dashboardId\":null,\n" + + " \"alarmDetails\":null\n" + + " }\n" + + " },\n" + + " \"propagateRelationTypes\":null\n" + + " }\n" + + " ],\n" + + " \"configuration\":{\n" + + " \"type\":\"DEFAULT\"\n" + + " },\n" + + " \"provisionConfiguration\":{\n" + + " \"type\":\"ALLOW_CREATE_NEW_DEVICES\",\n" + + " \"provisionDeviceSecret\":\"vaxb9hzqdbz3oqukvomg\"\n" + + " },\n" + + " \"transportConfiguration\":{\n" + + " \"type\":\"MQTT\",\n" + + " \"deviceTelemetryTopic\":\"v1/devices/me/telemetry\",\n" + + " \"deviceAttributesTopic\":\"v1/devices/me/attributes\",\n" + + " \"transportPayloadTypeConfiguration\":{\n" + + " \"transportPayloadType\":\"PROTOBUF\",\n" + + " \"deviceTelemetryProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage telemetry;\\n\\nmessage SensorDataReading {\\n\\n optional double temperature = 1;\\n optional double humidity = 2;\\n InnerObject innerObject = 3;\\n\\n message InnerObject {\\n optional string key1 = 1;\\n optional bool key2 = 2;\\n optional double key3 = 3;\\n optional int32 key4 = 4;\\n optional string key5 = 5;\\n }\\n}\",\n" + + " \"deviceAttributesProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage attributes;\\n\\nmessage SensorConfiguration {\\n optional string firmwareVersion = 1;\\n optional string serialNumber = 2;\\n}\",\n" + + " \"deviceRpcRequestProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage rpc;\\n\\nmessage RpcRequestMsg {\\n optional string method = 1;\\n optional int32 requestId = 2;\\n optional string params = 3;\\n}\",\n" + + " \"deviceRpcResponseProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage rpc;\\n\\nmessage RpcResponseMsg {\\n optional string payload = 1;\\n}\"\n" + + " }\n" + + " }\n" + + "}" + MARKDOWN_CODE_BLOCK_END; + private static final String DEVICE_PROFILE_DATA_DEFINITION = NEW_LINE + "# Device profile data definition" + NEW_LINE + + "Device profile data object contains alarm rules configuration, device provision strategy and transport type configuration for device connectivity. Let's review some examples. " + + "First one is the default device profile data configuration and second one - the custom one. " + + NEW_LINE + DEFAULT_DEVICE_PROFILE_DATA_EXAMPLE + NEW_LINE + CUSTOM_DEVICE_PROFILE_DATA_EXAMPLE + + NEW_LINE + "Let's review some specific objects examples related to the device profile configuration:"; + + private static final String ALARM_SCHEDULE = NEW_LINE + "# Alarm Schedule" + NEW_LINE + + "Alarm Schedule JSON object represents the time interval during which the alarm rule is active. Note, " + + NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE + NEW_LINE + "means alarm rule is active all the time. " + + "**'daysOfWeek'** field represents Monday as 1, Tuesday as 2 and so on. **'startsOn'** and **'endsOn'** fields represent hours in millis (e.g. 64800000 = 18:00 or 6pm). " + + "**'enabled'** flag specifies if item in a custom rule is active for specific day of the week:" + NEW_LINE + + "## Specific Time Schedule" + NEW_LINE + + DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE + NEW_LINE + + "## Custom Schedule" + + NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE + NEW_LINE; + + private static final String ALARM_CONDITION_TYPE = "# Alarm condition type (**'spec'**)" + NEW_LINE + + "Alarm condition type can be either simple, duration, or repeating. For example, 5 times in a row or during 5 minutes." + NEW_LINE + + "Note, **'userValue'** field is not used and reserved for future usage, **'dynamicValue'** is used for condition appliance by using the value of the **'sourceAttribute'** " + + "or else **'defaultValue'** is used (if **'sourceAttribute'** is absent).\n" + + "\n**'sourceType'** of the **'sourceAttribute'** can be: \n" + + " * 'CURRENT_DEVICE';\n" + + " * 'CURRENT_CUSTOMER';\n" + + " * 'CURRENT_TENANT'." + NEW_LINE + + "**'sourceAttribute'** can be inherited from the owner if **'inherit'** is set to true (for CURRENT_DEVICE and CURRENT_CUSTOMER)." + NEW_LINE + + "## Repeating alarm condition" + NEW_LINE + + DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE + NEW_LINE + + "## Duration alarm condition" + NEW_LINE + + DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE + NEW_LINE + + "**'unit'** can be: \n" + + " * 'SECONDS';\n" + + " * 'MINUTES';\n" + + " * 'HOURS';\n" + + " * 'DAYS'." + NEW_LINE; + + private static final String PROVISION_CONFIGURATION = "# Provision Configuration" + NEW_LINE + + "There are 3 types of device provision configuration for the device profile: \n" + + " * 'DISABLED';\n" + + " * 'ALLOW_CREATE_NEW_DEVICES';\n" + + " * 'CHECK_PRE_PROVISIONED_DEVICES'." + NEW_LINE + + "Please refer to the [docs](https://thingsboard.io/docs/user-guide/device-provisioning/) for more details." + NEW_LINE; + + private static final String DEVICE_PROFILE_DATA = DEVICE_PROFILE_DATA_DEFINITION + ALARM_SCHEDULE + ALARM_CONDITION_TYPE + + KEY_FILTERS_DESCRIPTION + PROVISION_CONFIGURATION + TRANSPORT_CONFIGURATION; + private static final String DEVICE_PROFILE_ID = "deviceProfileId"; @Autowired @@ -173,20 +620,9 @@ public class DeviceProfileController extends BaseController { notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + "The newly created device profile id will be present in the response. " + "Specify existing device profile id to update the device profile. " + - "Referencing non-existing device profile Id will cause 'Not Found' error. " + - "\n\nDevice profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + TENANT_AUTHORITY_PARAGRAPH + - NEW_LINE + "See the object example below for createRules field:" + NEW_LINE + DEVICE_PROFILE_ALARM_CREATE_RULES_EXAMPLE + - NEW_LINE + "See alarm schedule objects examples below. Note," + NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE + NEW_LINE + " means alarm rule is active all the time. " + - "'daysOfWeek' field represents Monday as 1, Tuesday as 2 and so on. 'startsOn' and 'endsOn' represent hours in millis. " + - "'enabled' flag represents if custom rule is active for specific day of the week:" + NEW_LINE + - DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE + NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE + NEW_LINE + - "Alarm condition type ('spec') can be either simple, duration, or repeating. For example, 5 times in a row or during 5 minutes. See examples below. " + NEW_LINE + - DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE + NEW_LINE + DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE + NEW_LINE + - "Note, 'userValue' field is not used, 'dynamicValue' is used for condition appliance from the 'sourceAttribute' or else 'defaultValue' is used. " + - "'sourceType' of the 'sourceAttribute' can be CURRENT_DEVICE/CURRENT_CUSTOMER/CURRENT_TENANT or inherited from the owner if set to true (for device and customer)." + - NEW_LINE + "Condition array examples for alarm rule activation:" + NEW_LINE + DEVICE_PROFILE_CONDITIONS_TIME_SERIES_NUMERIC_EXAMPLE + NEW_LINE + - DEVICE_PROFILE_CONDITIONS_CONSTANT_EXAMPLE + NEW_LINE + - "Note, see description of predicate fields above for 'spec' object. Navigate to Docs or Alarm Rules on ThingsBoard UI for more details and examples of fields possible values. ", + "Referencing non-existing device profile Id will cause 'Not Found' error. " + NEW_LINE + + "Device profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + DEVICE_PROFILE_DATA + + TENANT_AUTHORITY_PARAGRAPH, produces = "application/json", consumes = "application/json") @PreAuthorize("hasAuthority('TENANT_ADMIN')") diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 2e815bdc7e..dab2a55f50 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -45,7 +45,7 @@ import org.thingsboard.server.service.query.EntityQueryService; public class EntityQueryController extends BaseController { private static final String SINGLE_ENTITY = "\n\n## Single Entity\n\n" + - "Allows to filter only one entity based on the id. For example, this entity filter selects certain device:\n\n"+ + "Allows to filter only one entity based on the id. For example, this entity filter selects certain device:\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"singleEntity\",\n" + @@ -53,12 +53,12 @@ public class EntityQueryController extends BaseController { " \"id\": \"d521edb0-2a7a-11ec-94eb-213c95f54092\",\n" + " \"entityType\": \"DEVICE\"\n" + " }\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String ENTITY_LIST = "\n\n## Entity List Filter\n\n" + - "Allows to filter entities of the same type using their ids. For example, this entity filter selects two devices:\n\n"+ + "Allows to filter entities of the same type using their ids. For example, this entity filter selects two devices:\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"entityList\",\n" + @@ -67,84 +67,84 @@ public class EntityQueryController extends BaseController { " \"e6501f30-2a7a-11ec-94eb-213c95f54092\",\n" + " \"e6657bf0-2a7a-11ec-94eb-213c95f54092\"\n" + " ]\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String ENTITY_NAME = "\n\n## Entity Name Filter\n\n" + "Allows to filter entities of the same type using the **'starts with'** expression over entity name. " + - "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n"+ + "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"entityName\",\n" + " \"entityType\": \"DEVICE\",\n" + " \"entityNameFilter\": \"Air Quality\"\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String ENTITY_TYPE = "\n\n## Entity Type Filter\n\n" + "Allows to filter entities based on their type (CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, etc)" + - "For example, this entity filter selects all tenant customers:\n\n"+ + "For example, this entity filter selects all tenant customers:\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"entityType\",\n" + " \"entityType\": \"CUSTOMER\"\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String ASSET_TYPE = "\n\n## Asset Type Filter\n\n" + "Allows to filter assets based on their type and the **'starts with'** expression over their name. " + - "For example, this entity filter selects all 'charging station' assets which name starts with 'Tesla':\n\n"+ + "For example, this entity filter selects all 'charging station' assets which name starts with 'Tesla':\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"assetType\",\n" + " \"assetType\": \"charging station\",\n" + " \"assetNameFilter\": \"Tesla\"\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String DEVICE_TYPE = "\n\n## Device Type Filter\n\n" + "Allows to filter devices based on their type and the **'starts with'** expression over their name. " + - "For example, this entity filter selects all 'Temperature Sensor' devices which name starts with 'ABC':\n\n"+ + "For example, this entity filter selects all 'Temperature Sensor' devices which name starts with 'ABC':\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"deviceType\",\n" + " \"deviceType\": \"Temperature Sensor\",\n" + " \"deviceNameFilter\": \"ABC\"\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String EDGE_TYPE = "\n\n## Edge Type Filter\n\n" + "Allows to filter edge instances based on their type and the **'starts with'** expression over their name. " + - "For example, this entity filter selects all 'Factory' edge instances which name starts with 'Nevada':\n\n"+ + "For example, this entity filter selects all 'Factory' edge instances which name starts with 'Nevada':\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"edgeType\",\n" + " \"edgeType\": \"Factory\",\n" + " \"edgeNameFilter\": \"Nevada\"\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String ENTITY_VIEW_TYPE = "\n\n## Entity View Filter\n\n" + "Allows to filter entity views based on their type and the **'starts with'** expression over their name. " + - "For example, this entity filter selects all 'Concrete Mixer' entity views which name starts with 'CAT':\n\n"+ + "For example, this entity filter selects all 'Concrete Mixer' entity views which name starts with 'CAT':\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"entityViewType\",\n" + " \"entityViewType\": \"Concrete Mixer\",\n" + " \"entityViewNameFilter\": \"CAT\"\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String API_USAGE = "\n\n## Api Usage Filter\n\n" + "Allows to query for Api Usage based on optional customer id. If the customer id is not set, returns current tenant API usage." + - "For example, this entity filter selects the 'Api Usage' entity for customer with id 'e6501f30-2a7a-11ec-94eb-213c95f54092':\n\n"+ + "For example, this entity filter selects the 'Api Usage' entity for customer with id 'e6501f30-2a7a-11ec-94eb-213c95f54092':\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"apiUsageState\",\n" + @@ -152,7 +152,7 @@ public class EntityQueryController extends BaseController { " \"id\": \"d521edb0-2a7a-11ec-94eb-213c95f54092\",\n" + " \"entityType\": \"CUSTOMER\"\n" + " }\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; @@ -165,7 +165,7 @@ public class EntityQueryController extends BaseController { FETCH_LAST_LEVEL_ONLY_DESCRIPTION + "The 'filter' object allows you to define the relation type and set of acceptable entity types to search for. " + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only those who match the 'filters'.\n\n" + - "For example, this entity filter selects all devices and assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092':\n\n"+ + "For example, this entity filter selects all devices and assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092':\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"relationsQuery\",\n" + @@ -185,7 +185,7 @@ public class EntityQueryController extends BaseController { " ]\n" + " }\n" + " ]\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; @@ -197,7 +197,7 @@ public class EntityQueryController extends BaseController { "The 'relationType' defines the type of the relation to search for. " + "The 'assetTypes' defines the type of the asset to search for. " + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only assets that match 'relationType' and 'assetTypes' conditions.\n\n" + - "For example, this entity filter selects 'charging station' assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n"+ + "For example, this entity filter selects 'charging station' assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"assetSearchQuery\",\n" + @@ -212,7 +212,7 @@ public class EntityQueryController extends BaseController { " \"assetTypes\": [\n" + " \"charging station\"\n" + " ]\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; @@ -223,7 +223,7 @@ public class EntityQueryController extends BaseController { "The 'relationType' defines the type of the relation to search for. " + "The 'deviceTypes' defines the type of the device to search for. " + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + - "For example, this entity filter selects 'Charging port' and 'Air Quality Sensor' devices which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n"+ + "For example, this entity filter selects 'Charging port' and 'Air Quality Sensor' devices which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"deviceSearchQuery\",\n" + @@ -239,7 +239,7 @@ public class EntityQueryController extends BaseController { " \"Air Quality Sensor\",\n" + " \"Charging port\"\n" + " ]\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; @@ -250,7 +250,7 @@ public class EntityQueryController extends BaseController { "The 'relationType' defines the type of the relation to search for. " + "The 'entityViewTypes' defines the type of the entity view to search for. " + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + - "For example, this entity filter selects 'Concrete mixer' entity views which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n"+ + "For example, this entity filter selects 'Concrete mixer' entity views which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"entityViewSearchQuery\",\n" + @@ -265,7 +265,7 @@ public class EntityQueryController extends BaseController { " \"entityViewTypes\": [\n" + " \"Concrete mixer\"\n" + " ]\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; @@ -276,7 +276,7 @@ public class EntityQueryController extends BaseController { "The 'relationType' defines the type of the relation to search for. " + "The 'deviceTypes' defines the type of the device to search for. " + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + - "For example, this entity filter selects 'Factory' edge instances which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n"+ + "For example, this entity filter selects 'Factory' edge instances which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"deviceSearchQuery\",\n" + @@ -291,27 +291,27 @@ public class EntityQueryController extends BaseController { " \"edgeTypes\": [\n" + " \"Factory\"\n" + " ]\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; private static final String EMPTY = "\n\n## Entity Type Filter\n\n" + "Allows to filter multiple entities of the same type using the **'starts with'** expression over entity name. " + - "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n"+ + "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n" + MARKDOWN_CODE_BLOCK_START + - ""+ + "" + MARKDOWN_CODE_BLOCK_END + ""; private static final String ENTITY_FILTERS = "\n\n # Entity Filters" + - "\nEntity Filter body depends on the 'type' parameter. Let's review available entity filter types. In fact, they do correspond to available dashboard aliases." + - SINGLE_ENTITY + ENTITY_LIST + ENTITY_NAME + ENTITY_TYPE + ASSET_TYPE + DEVICE_TYPE + EDGE_TYPE + ENTITY_VIEW_TYPE + API_USAGE + RELATIONS_QUERY_FILTER - + ASSET_QUERY_FILTER + DEVICE_QUERY_FILTER + EV_QUERY_FILTER + EDGE_QUERY_FILTER; + "\nEntity Filter body depends on the 'type' parameter. Let's review available entity filter types. In fact, they do correspond to available dashboard aliases." + + SINGLE_ENTITY + ENTITY_LIST + ENTITY_NAME + ENTITY_TYPE + ASSET_TYPE + DEVICE_TYPE + EDGE_TYPE + ENTITY_VIEW_TYPE + API_USAGE + RELATIONS_QUERY_FILTER + + ASSET_QUERY_FILTER + DEVICE_QUERY_FILTER + EV_QUERY_FILTER + EDGE_QUERY_FILTER; private static final String FILTER_KEY = "\n\n## Filter Key\n\n" + "Filter Key defines either entity field, attribute or telemetry. It is a JSON object that consists the key name and type. " + - "The following filter key types are supported: \n\n"+ + "The following filter key types are supported: \n\n" + " * 'CLIENT_ATTRIBUTE' - used for client attributes; \n" + " * 'SHARED_ATTRIBUTE' - used for shared attributes; \n" + " * 'SERVER_ATTRIBUTE' - used for server attributes; \n" + @@ -328,19 +328,10 @@ public class EntityQueryController extends BaseController { MARKDOWN_CODE_BLOCK_END + ""; - private static final String FILTER_VALUE_TYPE = "\n\n## Value Type and Operations\n\n" + - "Provides a hint about the data type of the entity field that is defined in the filter key. " + - "The value type impacts the list of possible operations that you may use in the corresponding predicate. For example, you may use 'STARTS_WITH' or 'END_WITH', but you can't use 'GREATER_OR_EQUAL' for string values." + - "The following filter value types and corresponding predicate operations are supported: \n\n"+ - " * 'STRING' - used to filter any 'String' or 'JSON' values. Operations: EQUAL, NOT_EQUAL, STARTS_WITH, ENDS_WITH, CONTAINS, NOT_CONTAINS; \n" + - " * 'NUMERIC' - used for 'Long' and 'Double' values. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n" + - " * 'BOOLEAN' - used for boolean values; Operations: EQUAL, NOT_EQUAL \n" + - " * 'DATE_TIME' - similar to numeric, transforms value to milliseconds since epoch. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n"; - private static final String FILTER_PREDICATE = "\n\n## Filter Predicate\n\n" + "Filter Predicate defines the logical expression to evaluate. The list of available operations depends on the filter value type, see above. " + "Platform supports 4 predicate types: 'STRING', 'NUMERIC', 'BOOLEAN' and 'COMPLEX'. The last one allows to combine multiple operations over one filter key." + - "\n\nSimple predicate example to check 'value < 100': \n\n"+ + "\n\nSimple predicate example to check 'value < 100': \n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"operation\": \"LESS\",\n" + @@ -351,7 +342,7 @@ public class EntityQueryController extends BaseController { " \"type\": \"NUMERIC\"\n" + "}" + MARKDOWN_CODE_BLOCK_END + - "\n\nComplex predicate example, to check 'value < 10 or value > 20': \n\n"+ + "\n\nComplex predicate example, to check 'value < 10 or value > 20': \n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"COMPLEX\",\n" + @@ -376,7 +367,7 @@ public class EntityQueryController extends BaseController { " ]\n" + "}" + MARKDOWN_CODE_BLOCK_END + - "\n\nMore complex predicate example, to check 'value < 10 or (value > 50 && value < 60)': \n\n"+ + "\n\nMore complex predicate example, to check 'value < 10 or (value > 50 && value < 60)': \n\n" + MARKDOWN_CODE_BLOCK_START + "{\n" + " \"type\": \"COMPLEX\",\n" + @@ -461,16 +452,16 @@ public class EntityQueryController extends BaseController { private static final String ENTITY_COUNT_QUERY_DESCRIPTION = "Allows to run complex queries to search the count of platform entities (devices, assets, customers, etc) " + - "based on the combination of main entity filter and multiple key filters. Returns the number of entities that match the query definition.\n\n" + - "# Query Definition\n\n" + - "\n\nMain **entity filter** is mandatory and defines generic search criteria. " + + "based on the combination of main entity filter and multiple key filters. Returns the number of entities that match the query definition.\n\n" + + "# Query Definition\n\n" + + "\n\nMain **entity filter** is mandatory and defines generic search criteria. " + "For example, \"find all devices with profile 'Moisture Sensor'\" or \"Find all devices related to asset 'Building A'\"" + - "\n\nOptional **key filters** allow to filter results of the entity filter by complex criteria against " + - "main entity fields (name, label, type, etc), attributes and telemetry. " + - "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"."+ - "\n\nLet's review the example:" + - "\n\n" + MARKDOWN_CODE_BLOCK_START + - "{\n" + + "\n\nOptional **key filters** allow to filter results of the entity filter by complex criteria against " + + "main entity fields (name, label, type, etc), attributes and telemetry. " + + "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"." + + "\n\nLet's review the example:" + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + " \"entityFilter\": {\n" + " \"type\": \"entityType\",\n" + " \"entityType\": \"DEVICE\"\n" + @@ -492,12 +483,12 @@ public class EntityQueryController extends BaseController { " }\n" + " }\n" + " ]\n" + - "}"+ - MARKDOWN_CODE_BLOCK_END + - "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + - ENTITY_FILTERS + - KEY_FILTERS + - TENANT_AND_USER_AUTHORITY_PARAGRAPH;; + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + + ENTITY_FILTERS + + KEY_FILTERS + + TENANT_AND_USER_AUTHORITY_PARAGRAPH; private static final String ENTITY_DATA_QUERY_DESCRIPTION = "Allows to run complex queries over platform entities (devices, assets, customers, etc) " + @@ -508,7 +499,7 @@ public class EntityQueryController extends BaseController { "For example, \"find all devices with profile 'Moisture Sensor'\" or \"Find all devices related to asset 'Building A'\"" + "\n\nOptional **key filters** allow to filter results of the **entity filter** by complex criteria against " + "main entity fields (name, label, type, etc), attributes and telemetry. " + - "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"."+ + "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"." + "\n\nThe **entity fields** and **latest values** contains list of entity fields and latest attribute/telemetry fields to fetch for each entity." + "\n\nThe **page link** contains information about the page to fetch and the sort ordering." + "\n\nLet's review the example:" + @@ -575,7 +566,7 @@ public class EntityQueryController extends BaseController { " \"direction\": \"ASC\"\n" + " }\n" + " }\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + ENTITY_FILTERS + @@ -672,7 +663,7 @@ public class EntityQueryController extends BaseController { " \"key\": \"temperature\"\n" + " }\n" + " ]\n" + - "}"+ + "}" + MARKDOWN_CODE_BLOCK_END + ""; From 81bf7eaa88de49cc214cbe7939f0e381a0fe8fd0 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Wed, 20 Oct 2021 17:50:03 +0300 Subject: [PATCH 102/303] fixed typo of save device profile method --- .../thingsboard/server/controller/DeviceProfileController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index d826969415..9eb9ed4f84 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -616,7 +616,7 @@ public class DeviceProfileController extends BaseController { } } - @ApiOperation(value = "Create Or Update Device Profile (saveDevice)", + @ApiOperation(value = "Create Or Update Device Profile (saveDeviceProfile)", notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + "The newly created device profile id will be present in the response. " + "Specify existing device profile id to update the device profile. " + From f8da3104b7307b28ab1fe582f855e00c2c4c44ce Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 20 Oct 2021 18:28:25 +0300 Subject: [PATCH 103/303] UI: Updated dependencies: lodash and coreJS --- ui-ngx/package.json | 5 ++++- ui-ngx/yarn.lock | 16 ++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 2aaaff7b66..519d31b66c 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -43,7 +43,7 @@ "angular2-hotkeys": "^2.2.0", "canvas-gauges": "^2.1.7", "compass-sass-mixins": "^0.12.7", - "core-js": "^3.12.1", + "core-js": "^3.18.3", "date-fns": "^2.21.3", "flot": "git://github.com/thingsboard/flot.git#0.9-work", "flot.curvedlines": "git://github.com/MichaelZinsmaier/CurvedLines.git#master", @@ -143,5 +143,8 @@ "tslint": "~6.1.3", "typescript": "~4.0.3", "webpack": "^4.46.0" + }, + "resolutions": { + "lodash": "~4.17.21" } } diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index f07fd482e6..acb3a9eaa2 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -3465,10 +3465,10 @@ core-js@3.8.3: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.3.tgz#c21906e1f14f3689f93abcc6e26883550dd92dd0" integrity sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q== -core-js@^3.12.1: - version "3.12.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.12.1.tgz#6b5af4ff55616c08a44d386f1f510917ff204112" - integrity sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw== +core-js@^3.18.3: + version "3.18.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.3.tgz#86a0bba2d8ec3df860fefcc07a8d119779f01509" + integrity sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -6365,10 +6365,10 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== log-symbols@^4.0.0: version "4.0.0" From 106ba882936d62f028e8de623967d23d63f9e5dc Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 20 Oct 2021 20:12:08 +0300 Subject: [PATCH 104/303] Add rest of the widget functions help resources. Improved map widgets settings schema. --- .../json/system/widget_bundles/cards.json | 4 +- .../widget_bundles/control_widgets.json | 8 +- .../widget_bundles/entity_admin_widgets.json | 8 +- .../system/widget_bundles/gpio_widgets.json | 4 +- .../components/widget/lib/maps/schemes.ts | 208 +++++++++++++----- .../json-form/react/json-form-ace-editor.tsx | 2 +- .../src/app/shared/models/ace/ace.models.ts | 1 + .../help/en_US/widget/lib/map/color_fn.md | 42 ++++ .../help/en_US/widget/lib/map/label_fn.md | 40 ++++ .../help/en_US/widget/lib/map/map_fn_args.md | 10 + .../en_US/widget/lib/map/marker_image_fn.md | 62 ++++++ .../en_US/widget/lib/map/polygon_color_fn.md | 42 ++++ .../widget/lib/map/polygon_tooltip_fn.md | 40 ++++ .../help/en_US/widget/lib/map/position_fn.md | 41 ++++ .../help/en_US/widget/lib/map/tooltip_fn.md | 40 ++++ .../help/en_US/widget/lib/map/trip_fn_args.md | 11 + .../en_US/widget/lib/map/trip_label_fn.md | 40 ++++ .../widget/lib/map/trip_marker_image_fn.md | 62 ++++++ .../widget/lib/map/trip_path_color_fn.md | 42 ++++ .../lib/map/trip_path_point_color_fn.md | 43 ++++ .../widget/lib/map/trip_point_as_anchor_fn.md | 34 +++ .../en_US/widget/lib/map/trip_tooltip_fn.md | 40 ++++ .../en_US/widget/lib/rpc/convert_value_fn.md | 40 ++++ .../widget/lib/rpc/parse_gpio_status_fn.md | 35 +++ .../en_US/widget/lib/rpc/parse_value_fn.md | 41 ++++ 25 files changed, 876 insertions(+), 64 deletions(-) create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/label_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/map_fn_args.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/marker_image_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_tooltip_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/position_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/tooltip_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_fn_args.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_label_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_marker_image_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_color_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_point_color_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_point_as_anchor_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_tooltip_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/rpc/convert_value_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/rpc/parse_gpio_status_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/rpc/parse_value_fn.md diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 4fb124fc06..41aed542dd 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -163,7 +163,7 @@ "templateHtml": "\n", "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.qrCodeWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"QR Code\",\n \"properties\": {\n \"qrCodeTextPattern\": {\n \"title\": \"QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useQrCodeTextFunction\": {\n \"title\": \"Use QR code text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"qrCodeTextFunction\": {\n \"title\": \"QR code text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"qrCodeTextPattern\",\n \"condition\": \"model.useQrCodeTextFunction !== true\"\n },\n \"useQrCodeTextFunction\",\n {\n \"key\": \"qrCodeTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/qrcode/qrcode_text_fn\",\n \"condition\": \"model.useQrCodeTextFunction === true\"\n }\n ]\n}\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"QR Code\",\n \"properties\": {\n \"qrCodeTextPattern\": {\n \"title\": \"QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useQrCodeTextFunction\": {\n \"title\": \"Use QR code text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"qrCodeTextFunction\": {\n \"title\": \"QR code text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useQrCodeTextFunction\",\n {\n \"key\": \"qrCodeTextPattern\",\n \"condition\": \"model.useQrCodeTextFunction !== true\"\n },\n {\n \"key\": \"qrCodeTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/qrcode/qrcode_text_fn\",\n \"condition\": \"model.useQrCodeTextFunction === true\"\n }\n ]\n}\n", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7036904308224163,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"qrCodeTextPattern\":\"${entityName}\",\"useQrCodeTextFunction\":false,\"qrCodeTextFunction\":\"return data[0] ? data[0]['entityName'] : '';\"},\"title\":\"QR Code\"}" } @@ -181,7 +181,7 @@ "templateHtml": "\n", "templateCss": "#container tb-markdown-widget {\n height: 100%;\n display: block;\n}\n\n#container tb-markdown-widget .tb-markdown-view {\n height: 100%;\n overflow: auto;\n}\n", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.markdownWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\",\n \"condition\": \"model.useMarkdownTextFunction !== true\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n },\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/markdown/markdown_text_fn\",\n \"condition\": \"model.useMarkdownTextFunction === true\"\n }\n ]\n}\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\",\n \"condition\": \"model.useMarkdownTextFunction !== true\"\n },\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/markdown/markdown_text_fn\",\n \"condition\": \"model.useMarkdownTextFunction === true\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n }\n ]\n}\n", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown/HTML card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\",\"useMarkdownTextFunction\":false},\"title\":\"Markdown/HTML Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" } 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 7925e67ffd..f1e3eaa1fe 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 @@ -73,7 +73,7 @@ "templateHtml": "", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\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 \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\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 \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\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 \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\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 \"helpId\": \"widget/lib/rpc/parse_value_fn\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/convert_value_fn\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", "dataKeySettingsSchema": "{}\n", "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}" } @@ -91,7 +91,7 @@ "templateHtml": "", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\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 \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\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 \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\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 \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\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 \"helpId\": \"widget/lib/rpc/parse_value_fn\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/convert_value_fn\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", "dataKeySettingsSchema": "{}\n", "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}" } @@ -109,7 +109,7 @@ "templateHtml": "", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\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 \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\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 \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\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 \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\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 \"helpId\": \"widget/lib/rpc/parse_value_fn\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", "dataKeySettingsSchema": "{}\n", "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}" } @@ -151,4 +151,4 @@ } } ] -} +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/entity_admin_widgets.json b/application/src/main/data/json/system/widget_bundles/entity_admin_widgets.json index 9e1d92d0fd..5fdced278b 100644 --- a/application/src/main/data/json/system/widget_bundles/entity_admin_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/entity_admin_widgets.json @@ -19,8 +19,8 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"entitiesTitle\":\"Device admin table\",\"enableSelectColumnDisplay\":true},\"title\":\"Device admin table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{\"headerButton\":[{\"name\":\"Add device\",\"icon\":\"add\",\"type\":\"customPretty\",\"customHtml\":\"
    \\n \\n

    Add device

    \\n \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n \\n Device name\\n \\n \\n Device name is required.\\n \\n \\n
    \\n \\n \\n Label\\n \\n \\n
    \\n
    \\n \\n Latitude\\n \\n \\n \\n Longitude\\n \\n \\n
    \\n
    \\n
    \\n
    \\n \\n \\n \\n
    \\n
    \\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenAddDeviceDialog();\\n\\nfunction openAddDeviceDialog() {\\n customDialog.customDialog(htmlTemplate, AddDeviceDialogController).subscribe();\\n}\\n\\nfunction AddDeviceDialogController(instance) {\\n let vm = instance;\\n \\n vm.addDeviceFormGroup = vm.fb.group({\\n deviceName: ['', [vm.validators.required]],\\n deviceType: ['', [vm.validators.required]],\\n deviceLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.addDeviceFormGroup.markAsPristine();\\n let device = {\\n name: vm.addDeviceFormGroup.get('deviceName').value,\\n type: vm.addDeviceFormGroup.get('deviceType').value,\\n label: vm.addDeviceFormGroup.get('deviceLabel').value\\n };\\n deviceService.saveDevice(device).subscribe(\\n function (device) {\\n saveAttributes(device.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n function saveAttributes(entityId) {\\n let attributes = vm.addDeviceFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, \\\"SERVER_SCOPE\\\", attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"70837a9d-c3de-a9a7-03c5-dccd14998758\"}],\"actionCellButton\":[{\"name\":\"Edit device\",\"icon\":\"edit\",\"type\":\"customPretty\",\"customHtml\":\"
    \\n \\n

    Edit device

    \\n \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n \\n Device name\\n \\n \\n Device name is required.\\n \\n \\n
    \\n \\n \\n Label\\n \\n \\n
    \\n
    \\n \\n Latitude\\n \\n \\n \\n Longitude\\n \\n \\n
    \\n
    \\n
    \\n
    \\n \\n \\n \\n
    \\n
    \\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenEditDeviceDialog();\\n\\nfunction openEditDeviceDialog() {\\n customDialog.customDialog(htmlTemplate, EditDeviceDialogController).subscribe();\\n}\\n\\nfunction EditDeviceDialogController(instance) {\\n let vm = instance;\\n \\n vm.device = null;\\n vm.attributes = {};\\n \\n vm.editDeviceFormGroup = vm.fb.group({\\n deviceName: ['', [vm.validators.required]],\\n deviceType: ['', [vm.validators.required]],\\n deviceLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.editDeviceFormGroup.markAsPristine();\\n vm.device.name = vm.editDeviceFormGroup.get('deviceName').value,\\n vm.device.type = vm.editDeviceFormGroup.get('deviceType').value,\\n vm.device.label = vm.editDeviceFormGroup.get('deviceLabel').value\\n deviceService.saveDevice(vm.device).subscribe(\\n function () {\\n saveAttributes().subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n getEntityInfo();\\n \\n function getEntityInfo() {\\n deviceService.getDevice(entityId.id).subscribe(\\n function (device) {\\n attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',\\n ['latitude', 'longitude']).subscribe(\\n function (attributes) {\\n for (let i = 0; i < attributes.length; i++) {\\n vm.attributes[attributes[i].key] = attributes[i].value; \\n }\\n vm.device = device;\\n vm.editDeviceFormGroup.patchValue(\\n {\\n deviceName: vm.device.name,\\n deviceType: vm.device.type,\\n deviceLabel: vm.device.label,\\n attributes: {\\n latitude: vm.attributes.latitude,\\n longitude: vm.attributes.longitude\\n }\\n }, {emitEvent: false}\\n );\\n } \\n );\\n }\\n ); \\n }\\n \\n function saveAttributes() {\\n let attributes = vm.editDeviceFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"93931e52-5d7c-903e-67aa-b9435df44ff4\"},{\"name\":\"Delete device\",\"icon\":\"delete\",\"type\":\"custom\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\n\\nopenDeleteDeviceDialog();\\n\\nfunction openDeleteDeviceDialog() {\\n let title = \\\"Are you sure you want to delete the device \\\" + entityName + \\\"?\\\";\\n let content = \\\"Be careful, after the confirmation, the device and all related data will become unrecoverable!\\\";\\n dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(\\n function (result) {\\n if (result) {\\n deleteDevice();\\n }\\n }\\n );\\n}\\n\\nfunction deleteDevice() {\\n deviceService.deleteDevice(entityId.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n }\\n );\\n}\\n\",\"id\":\"ec2708f6-9ff0-186b-e4fc-7635ebfa3074\"}]}}" } }, @@ -37,8 +37,8 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"entitiesTitle\":\"Asset admin table\",\"enableSelectColumnDisplay\":true},\"title\":\"Asset admin table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{\"headerButton\":[{\"name\":\"Add asset\",\"icon\":\"add\",\"type\":\"customPretty\",\"customHtml\":\"
    \\n \\n

    Add asset

    \\n \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n \\n Asset name\\n \\n \\n Asset name is required.\\n \\n \\n
    \\n \\n \\n Label\\n \\n \\n
    \\n
    \\n \\n Latitude\\n \\n \\n \\n Longitude\\n \\n \\n
    \\n
    \\n
    \\n
    \\n \\n \\n \\n
    \\n
    \\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenAddAssetDialog();\\n\\nfunction openAddAssetDialog() {\\n customDialog.customDialog(htmlTemplate, AddAssetDialogController).subscribe();\\n}\\n\\nfunction AddAssetDialogController(instance) {\\n let vm = instance;\\n \\n vm.addAssetFormGroup = vm.fb.group({\\n assetName: ['', [vm.validators.required]],\\n assetType: ['', [vm.validators.required]],\\n assetLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.addAssetFormGroup.markAsPristine();\\n let asset = {\\n name: vm.addAssetFormGroup.get('assetName').value,\\n type: vm.addAssetFormGroup.get('assetType').value,\\n label: vm.addAssetFormGroup.get('assetLabel').value\\n };\\n assetService.saveAsset(asset).subscribe(\\n function (asset) {\\n saveAttributes(asset.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n function saveAttributes(entityId) {\\n let attributes = vm.addAssetFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, \\\"SERVER_SCOPE\\\", attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"70837a9d-c3de-a9a7-03c5-dccd14998758\"}],\"actionCellButton\":[{\"name\":\"Edit asset\",\"icon\":\"edit\",\"type\":\"customPretty\",\"customHtml\":\"
    \\n \\n

    Edit asset

    \\n \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n \\n Asset name\\n \\n \\n Asset name is required.\\n \\n \\n
    \\n \\n \\n Label\\n \\n \\n
    \\n
    \\n \\n Latitude\\n \\n \\n \\n Longitude\\n \\n \\n
    \\n
    \\n
    \\n
    \\n \\n \\n \\n
    \\n
    \\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenEditAssetDialog();\\n\\nfunction openEditAssetDialog() {\\n customDialog.customDialog(htmlTemplate, EditAssetDialogController).subscribe();\\n}\\n\\nfunction EditAssetDialogController(instance) {\\n let vm = instance;\\n \\n vm.asset = null;\\n vm.attributes = {};\\n \\n vm.editAssetFormGroup = vm.fb.group({\\n assetName: ['', [vm.validators.required]],\\n assetType: ['', [vm.validators.required]],\\n assetLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.editAssetFormGroup.markAsPristine();\\n vm.asset.name = vm.editAssetFormGroup.get('assetName').value,\\n vm.asset.type = vm.editAssetFormGroup.get('assetType').value,\\n vm.asset.label = vm.editAssetFormGroup.get('assetLabel').value\\n assetService.saveAsset(vm.asset).subscribe(\\n function () {\\n saveAttributes().subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n getEntityInfo();\\n \\n function getEntityInfo() {\\n assetService.getAsset(entityId.id).subscribe(\\n function (asset) {\\n attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',\\n ['latitude', 'longitude']).subscribe(\\n function (attributes) {\\n for (let i = 0; i < attributes.length; i++) {\\n vm.attributes[attributes[i].key] = attributes[i].value; \\n }\\n vm.asset = asset;\\n vm.editAssetFormGroup.patchValue(\\n {\\n assetName: vm.asset.name,\\n assetType: vm.asset.type,\\n assetLabel: vm.asset.label,\\n attributes: {\\n latitude: vm.attributes.latitude,\\n longitude: vm.attributes.longitude\\n }\\n }, {emitEvent: false}\\n );\\n } \\n );\\n }\\n ); \\n }\\n \\n function saveAttributes() {\\n let attributes = vm.editAssetFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"93931e52-5d7c-903e-67aa-b9435df44ff4\"},{\"name\":\"Delete asset\",\"icon\":\"delete\",\"type\":\"custom\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\n\\nopenDeleteAssetDialog();\\n\\nfunction openDeleteAssetDialog() {\\n let title = \\\"Are you sure you want to delete the asset \\\" + entityName + \\\"?\\\";\\n let content = \\\"Be careful, after the confirmation, the asset and all related data will become unrecoverable!\\\";\\n dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(\\n function (result) {\\n if (result) {\\n deleteAsset();\\n }\\n }\\n );\\n}\\n\\nfunction deleteAsset() {\\n assetService.deleteAsset(entityId.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n }\\n );\\n}\\n\",\"id\":\"ec2708f6-9ff0-186b-e4fc-7635ebfa3074\"}]}}" } } diff --git a/application/src/main/data/json/system/widget_bundles/gpio_widgets.json b/application/src/main/data/json/system/widget_bundles/gpio_widgets.json index 6ca5222f16..41583a4a8f 100644 --- a/application/src/main/data/json/system/widget_bundles/gpio_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/gpio_widgets.json @@ -19,7 +19,7 @@ "templateHtml": "
    \n
    \n
    \n
    \n {{ cell.label }}\n
    \n {{cell.pin}}\n \n \n \n \n {{cell.pin}}\n
    \n {{ cell.label }}\n
    \n
    \n \n \n \n
    \n
    \n
    \n {{rpcErrorText}}\n \n
    ", "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.gpio-panel section[fxflex] {\n min-width: 0px;\n}\n\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\n margin-left: 4px;\n margin-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", "controllerScript": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-control-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\n \n var i, gpio;\n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n scope.gpioList = [];\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false\n }\n );\n }\n\n scope.requestTimeout = settings.requestTimeout || 1000;\n\n scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioStatusRequest = {\n method: \"getGpioStatus\",\n paramsBody: \"{}\"\n };\n \n if (settings.gpioStatusRequest) {\n scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n }\n \n scope.gpioStatusChangeRequest = {\n method: \"setGpioStatus\",\n paramsBody: \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n };\n \n if (settings.gpioStatusChangeRequest) {\n scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n }\n \n scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n \n if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n }\n \n scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n \n function requestGpioStatus() {\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n scope.gpioStatusRequest.paramsBody, \n scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n for (var g = 0; g < scope.gpioList.length; g++) {\n var gpio = scope.gpioList[g];\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled; \n self.ctx.detectChanges();\n }\n }\n );\n }\n \n function changeGpioStatus(gpio) {\n var pin = gpio.pin + '';\n var enabled = !gpio.enabled;\n enabled = enabled === true ? 'true' : 'false';\n var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n requestBody, scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n self.ctx.detectChanges();\n }\n );\n }\n \n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n }\n\n scope.gpioClick = function($event, gpio) {\n if (scope.rpcEnabled && !scope.executingRpcRequest) {\n changeGpioStatus(gpio);\n }\n };\n \n scope.gpioToggleChange = function($event, gpio) {\n gpio.enabled = !$event.checked;\n $event.source.toggle();\n self.ctx.detectChanges();\n }\n \n if (scope.rpcEnabled) {\n requestGpioStatus(); \n }\n \n self.onResize();\n}\n\nself.onResize = function() {\n var scope = self.ctx.$scope;\n var rowCount = scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n scope.prefferedRowHeight = prefferedRowHeight;\n var ratio = prefferedRowHeight/32;\n \n var css = '.mat-slide-toggle .mat-slide-toggle-bar {\\n' +\n ' height: ' + 14*ratio+'px;\\n'+\n ' width: ' + 36*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb-container {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-ripple {\\n' +\n ' height: ' + 40*ratio+'px;\\n'+\n ' width: ' + 40*ratio+'px;\\n'+\n ' top: calc(50% - '+20*ratio+'px);\\n'+\n ' left: calc(50% - '+20*ratio+'px);\\n'+\n '}\\n';\n css += '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n\n cssParser.createStyleElement(namespace, css);\n \n self.ctx.detectChanges();\n}\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/parse_gpio_status_fn\"\n }\n ]\n}", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#b71c1c\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"_uniqueKey\":2}]},\"title\":\"Basic GPIO Control\"}" } @@ -73,7 +73,7 @@ "templateHtml": "
    \n
    \n
    \n
    \n {{ cell.label }}\n
    \n {{cell.pin}}\n \n \n \n \n {{cell.pin}}\n
    \n {{ cell.label }}\n
    \n
    \n \n \n \n
    \n
    \n
    \n {{rpcErrorText}}\n \n
    ", "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.gpio-panel section[fxflex] {\n min-width: 0px;\n}\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\n margin-left: 4px;\n margin-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", "controllerScript": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-control-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\n \n var i, gpio;\n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n scope.gpioList = [];\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false\n }\n );\n }\n\n scope.requestTimeout = settings.requestTimeout || 1000;\n\n scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioStatusRequest = {\n method: \"getGpioStatus\",\n paramsBody: \"{}\"\n };\n \n if (settings.gpioStatusRequest) {\n scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n }\n \n scope.gpioStatusChangeRequest = {\n method: \"setGpioStatus\",\n paramsBody: \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n };\n \n if (settings.gpioStatusChangeRequest) {\n scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n }\n \n scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n \n if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n }\n \n scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n \n function requestGpioStatus() {\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n scope.gpioStatusRequest.paramsBody, \n scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n for (var g = 0; g < scope.gpioList.length; g++) {\n var gpio = scope.gpioList[g];\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled; \n self.ctx.detectChanges();\n }\n }\n );\n }\n \n function changeGpioStatus(gpio) {\n var pin = gpio.pin + '';\n var enabled = !gpio.enabled;\n enabled = enabled === true ? 'true' : 'false';\n var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n requestBody, scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n self.ctx.detectChanges();\n }\n );\n }\n \n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n }\n\n scope.gpioClick = function($event, gpio) {\n if (scope.rpcEnabled && !scope.executingRpcRequest) {\n changeGpioStatus(gpio);\n }\n };\n \n scope.gpioToggleChange = function($event, gpio) {\n gpio.enabled = !$event.checked;\n $event.source.toggle();\n self.ctx.detectChanges();\n }\n \n if (scope.rpcEnabled) {\n requestGpioStatus(); \n }\n \n self.onResize();\n}\n\nself.onResize = function() {\n var scope = self.ctx.$scope;\n var rowCount = scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n scope.prefferedRowHeight = prefferedRowHeight;\n var ratio = prefferedRowHeight/32;\n \n var css = '.mat-slide-toggle .mat-slide-toggle-bar {\\n' +\n ' height: ' + 14*ratio+'px;\\n'+\n ' width: ' + 36*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb-container {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-ripple {\\n' +\n ' height: ' + 40*ratio+'px;\\n'+\n ' width: ' + 40*ratio+'px;\\n'+\n ' top: calc(50% - '+20*ratio+'px);\\n'+\n ' left: calc(50% - '+20*ratio+'px);\\n'+\n '}\\n';\n css += '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n\n cssParser.createStyleElement(namespace, css);\n \n self.ctx.detectChanges();\n}\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/parse_gpio_status_fn\"\n }\n ]\n}", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#008a00\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":7,\"label\":\"GPIO 4 (GPCLK0)\",\"row\":3,\"col\":0,\"_uniqueKey\":0},{\"pin\":11,\"label\":\"GPIO 17\",\"row\":5,\"col\":0,\"_uniqueKey\":1},{\"pin\":12,\"label\":\"GPIO 18\",\"row\":5,\"col\":1,\"_uniqueKey\":2},{\"_uniqueKey\":3,\"pin\":13,\"label\":\"GPIO 27\",\"row\":6,\"col\":0},{\"_uniqueKey\":4,\"pin\":15,\"label\":\"GPIO 22\",\"row\":7,\"col\":0},{\"_uniqueKey\":5,\"pin\":16,\"label\":\"GPIO 23\",\"row\":7,\"col\":1},{\"_uniqueKey\":6,\"pin\":18,\"label\":\"GPIO 24\",\"row\":8,\"col\":1},{\"_uniqueKey\":7,\"pin\":22,\"label\":\"GPIO 25\",\"row\":10,\"col\":1},{\"_uniqueKey\":8,\"pin\":29,\"label\":\"GPIO 5\",\"row\":14,\"col\":0},{\"_uniqueKey\":9,\"pin\":31,\"label\":\"GPIO 6\",\"row\":15,\"col\":0},{\"_uniqueKey\":10,\"pin\":32,\"label\":\"GPIO 12\",\"row\":15,\"col\":1},{\"_uniqueKey\":11,\"pin\":33,\"label\":\"GPIO 13\",\"row\":16,\"col\":0},{\"_uniqueKey\":12,\"pin\":35,\"label\":\"GPIO 19\",\"row\":17,\"col\":0},{\"_uniqueKey\":13,\"pin\":36,\"label\":\"GPIO 16\",\"row\":17,\"col\":1},{\"_uniqueKey\":14,\"pin\":37,\"label\":\"GPIO 26\",\"row\":18,\"col\":0},{\"_uniqueKey\":15,\"pin\":38,\"label\":\"GPIO 20\",\"row\":18,\"col\":1},{\"_uniqueKey\":16,\"pin\":40,\"label\":\"GPIO 21\",\"row\":19,\"col\":1}]},\"title\":\"Raspberry Pi GPIO Control\"}" } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index 0287cb17d8..d7110f0a4b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -431,11 +431,19 @@ export const commonMapSettingsSchema = condition: 'model.provider === "image-map"' }, 'showLabel', - 'label', - 'useLabelFunction', + { + key: 'useLabelFunction', + condition: 'model.showLabel === true' + }, + { + key: 'label', + condition: 'model.showLabel === true && model.useLabelFunction !== true' + }, { key: 'labelFunction', - type: 'javascript' + type: 'javascript', + helpId: 'widget/lib/map/label_fn', + condition: 'model.showLabel === true && model.useLabelFunction === true' }, 'showTooltip', { @@ -451,17 +459,27 @@ export const commonMapSettingsSchema = value: 'hover', label: 'Show tooltip on hover' } - ] + ], + condition: 'model.showTooltip === true' + }, + { + key: 'autocloseTooltip', + condition: 'model.showTooltip === true' + }, + { + key: 'useTooltipFunction', + condition: 'model.showTooltip === true' }, - 'autocloseTooltip', { key: 'tooltipPattern', - type: 'textarea' + type: 'textarea', + condition: 'model.showTooltip === true && model.useTooltipFunction !== true' }, - 'useTooltipFunction', { key: 'tooltipFunction', - type: 'javascript' + type: 'javascript', + helpId: 'widget/lib/map/tooltip_fn', + condition: 'model.showTooltip === true && model.useTooltipFunction === true' }, { key: 'markerOffsetX', @@ -474,6 +492,7 @@ export const commonMapSettingsSchema = { key: 'posFunction', type: 'javascript', + helpId: 'widget/lib/map/position_fn', condition: 'model.provider === "image-map"' }, { @@ -483,17 +502,25 @@ export const commonMapSettingsSchema = 'useColorFunction', { key: 'colorFunction', - type: 'javascript' + type: 'javascript', + helpId: 'widget/lib/map/color_fn', + condition: 'model.useColorFunction === true' }, + 'useMarkerImageFunction', { key: 'markerImage', - type: 'image' + type: 'image', + condition: 'model.useMarkerImageFunction !== true' + }, + { + key: 'markerImageSize', + condition: 'model.useMarkerImageFunction !== true' }, - 'markerImageSize', - 'useMarkerImageFunction', { key: 'markerImageFunction', - type: 'javascript' + type: 'javascript', + helpId: 'widget/lib/map/marker_image_fn', + condition: 'model.useMarkerImageFunction === true' }, { key: 'markerImages', @@ -502,7 +529,8 @@ export const commonMapSettingsSchema = key: 'markerImages[]', type: 'image' } - ] + ], + condition: 'model.useMarkerImageFunction === true' } ] }; @@ -590,24 +618,36 @@ export const mapPolygonSchema = key: 'polygonColor', type: 'color' }, + 'usePolygonColorFunction', + { + key: 'polygonColorFunction', + helpId: 'widget/lib/map/polygon_color_fn', + type: 'javascript', + condition: 'model.usePolygonColorFunction === true' + }, 'polygonOpacity', { key: 'polygonStrokeColor', type: 'color' }, - 'polygonStrokeOpacity', 'polygonStrokeWeight', 'showPolygonTooltip', + 'polygonStrokeOpacity', + 'polygonStrokeWeight', + 'showPolygonTooltip', { - key: 'polygonTooltipPattern', - type: 'textarea' - }, 'usePolygonTooltipFunction', { - key: 'polygonTooltipFunction', - type: 'javascript' + key: 'usePolygonTooltipFunction', + condition: 'model.showPolygonTooltip === true' }, - 'usePolygonColorFunction', { - key: 'polygonColorFunction', - type: 'javascript' + key: 'polygonTooltipPattern', + type: 'textarea', + condition: 'model.showPolygonTooltip === true && model.usePolygonTooltipFunction !== true' }, + { + key: 'polygonTooltipFunction', + helpId: 'widget/lib/map/polygon_tooltip_fn', + type: 'javascript', + condition: 'model.showPolygonTooltip === true && model.usePolygonTooltipFunction === true' + } ] }; @@ -822,11 +862,18 @@ export const pathSchema = { key: 'color', type: 'color' - }, 'useColorFunction', { + }, + 'useColorFunction', + { key: 'colorFunction', - type: 'javascript' - }, 'strokeWeight', 'strokeOpacity', - 'usePolylineDecorator', { + helpId: 'widget/lib/map/trip_path_color_fn', + type: 'javascript', + condition: 'model.useColorFunction === true' + }, + 'strokeWeight', + 'strokeOpacity', + 'usePolylineDecorator', + { key: 'decoratorSymbol', type: 'rc-select', multiple: false, @@ -837,16 +884,22 @@ export const pathSchema = value: 'dash', label: 'Dash' }] - }, 'decoratorSymbolSize', 'useDecoratorCustomColor', { + }, + 'decoratorSymbolSize', + 'useDecoratorCustomColor', + { key: 'decoratorCustomColor', type: 'color' - }, { + }, + { key: 'decoratorOffset', type: 'textarea' - }, { + }, + { key: 'endDecoratorOffset', type: 'textarea' - }, { + }, + { key: 'decoratorRepeat', type: 'textarea' } @@ -856,7 +909,7 @@ export const pathSchema = export const pointSchema = { schema: { - title: 'Trip Animation Path Configuration', + title: 'Trip Animation Points Configuration', type: 'object', properties: { showPoints: { @@ -908,13 +961,17 @@ export const pointSchema = 'useColorPointFunction', { key: 'colorPointFunction', - type: 'javascript' + helpId: 'widget/lib/map/trip_path_point_color_fn', + type: 'javascript', + condition: 'model.useColorPointFunction === true' }, 'pointSize', 'usePointAsAnchor', { key: 'pointAsAnchorFunction', - type: 'javascript' + helpId: 'widget/lib/map/trip_point_as_anchor_fn', + type: 'javascript', + condition: 'model.usePointAsAnchor === true' }, 'pointTooltipOnRightPanel', ] @@ -1077,36 +1134,85 @@ export const tripAnimationSchema = { }, required: [] }, - form: ['normalizationStep', 'latKeyName', 'lngKeyName', 'showLabel', 'label', 'useLabelFunction', { + form: [ + 'normalizationStep', + 'latKeyName', + 'lngKeyName', + 'showLabel', + { + key: 'useLabelFunction', + condition: 'model.showLabel === true' + }, + { + key: 'label', + condition: 'model.showLabel === true && model.useLabelFunction !== true' + }, + { key: 'labelFunction', - type: 'javascript' - }, 'showTooltip', { + type: 'javascript', + helpId: 'widget/lib/map/trip_label_fn', + condition: 'model.showLabel === true && model.useLabelFunction === true' + }, + 'showTooltip', + { key: 'tooltipColor', - type: 'color' - }, { + type: 'color', + condition: 'model.showTooltip === true' + }, + { key: 'tooltipFontColor', - type: 'color' - }, 'tooltipOpacity', { + type: 'color', + condition: 'model.showTooltip === true' + }, + { + key: 'tooltipOpacity', + condition: 'model.showTooltip === true' + }, + { + key: 'autocloseTooltip', + condition: 'model.showTooltip === true' + }, + { + key: 'useTooltipFunction', + condition: 'model.showTooltip === true', + }, + { key: 'tooltipPattern', - type: 'textarea' - }, 'useTooltipFunction', { + type: 'textarea', + condition: 'model.showTooltip === true && model.useTooltipFunction !== true' + }, + { key: 'tooltipFunction', - type: 'javascript' - }, 'autocloseTooltip', { + type: 'javascript', + helpId: 'widget/lib/map/trip_tooltip_fn', + condition: 'model.showTooltip === true && model.useTooltipFunction === true' + }, + 'rotationAngle', + 'useMarkerImageFunction', + { key: 'markerImage', - type: 'image' - }, 'markerImageSize', 'rotationAngle', 'useMarkerImageFunction', - { + type: 'image', + condition: 'model.useMarkerImageFunction !== true' + }, + { + key: 'markerImageSize', + condition: 'model.useMarkerImageFunction !== true' + }, + { key: 'markerImageFunction', - type: 'javascript' - }, { + type: 'javascript', + helpId: 'widget/lib/map/trip_marker_image_fn', + condition: 'model.useMarkerImageFunction === true' + }, + { key: 'markerImages', items: [ { key: 'markerImages[]', type: 'image' } - ] + ], + condition: 'model.useMarkerImageFunction === true' }] }; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx index db6042f450..dc5402c044 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx @@ -205,9 +205,9 @@ class ThingsboardAceEditor extends React.Component Loading...}> { aceObservables.push(from(import('ace-builds/src-noconflict/snippets/text'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/markdown'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/html'))); + aceObservables.push(from(import('ace-builds/src-noconflict/theme-textmate'))); aceObservables.push(from(import('ace-builds/src-noconflict/theme-github'))); return forkJoin(aceObservables).pipe( tap(() => { diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md new file mode 100644 index 0000000000..64e994fc3e --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md @@ -0,0 +1,42 @@ +#### Marker color function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute color of the marker. + +**Parameters:** + +
      + {% include widget/lib/map/map_fn_args %} +
    + +**Returns:** + +Should return string value presenting color of the marker. + +In case no data is returned, color value from **Color** settings field will be used. + +
    + +##### Examples + +* Calculate color depending on `temperature` telemetry value for `colorpin` device type: + +```javascript +var type = data['Type']; +if (type == 'colorpin') { + var temperature = data['temperature']; + if (typeof temperature !== undefined) { + var percent = (temperature + 60)/120 * 100; + return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + } + return 'blue'; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/label_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/label_fn.md new file mode 100644 index 0000000000..eb3e6f981e --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/label_fn.md @@ -0,0 +1,40 @@ +#### Marker label function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute text or HTML code of the marker label. + +**Parameters:** + +
      + {% include widget/lib/map/map_fn_args %} +
    + +**Returns:** + +Should return string value presenting text or HTML of the marker label. + +
    + +##### Examples + +* Display styled label with corresponding latest telemetry data for `energy meter` or `thermometer` device types: + +```javascript +var deviceType = data['Type']; +if (typeof deviceType !== undefined) { + if (deviceType == "energy meter") { + return '${entityName}, ${energy:2} kWt'; + } else if (deviceType == "thermometer") { + return '${entityName}, ${temperature:2} °C'; + } +} +return data.entityName; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/map_fn_args.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/map_fn_args.md new file mode 100644 index 0000000000..d1275ee871 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/map_fn_args.md @@ -0,0 +1,10 @@ +
  • data: FormattedData - A FormattedData object associated with marker.
    + Represents basic entity properties (ex. entityId, entityName)
    and provides access to other entity attributes/timeseries declared in widget datasource configuration. +
  • +
  • dsData: FormattedData[] - All available widget data (entities) as array of FormattedData objects
    + resolved from configured datasources. Each object represents basic entity properties (ex. entityId, entityName)
    + and provides access to other entity attributes/timeseries declared in widget datasource configuration. +
  • +
  • dsIndex number - index of the current marker data in dsData array.
    + Note: The data argument is equivalent to dsData[dsIndex] expression. +
  • diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/marker_image_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/marker_image_fn.md new file mode 100644 index 0000000000..565de0147a --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/marker_image_fn.md @@ -0,0 +1,62 @@ +#### Marker image function + +
    +
    + +*function (data, images, dsData, dsIndex): {url: string, size: number}* + +A JavaScript function used to compute marker image. + +**Parameters:** + +
      + {% include widget/lib/map/map_fn_args %} +
    + +**Returns:** + +Should return marker image data having the following structure: + +```typescript +{ + url: string, + size: number +} +``` + +- *url* - marker image url; +- *size* - marker image size; + +In case no data is returned, default marker image will be used. + +
    + +##### Examples + +
      +
    • +Calculate image url depending on temperature telemetry value for thermometer device type.
      +Let's assume 4 images are defined in Marker images section. Each image corresponds to particular temperature level: +
    • +
    + +```javascript +var type = data['Type']; +if (type == 'thermometer') { + var res = { + url: images[0], + size: 40 + } + var temperature = data['temperature']; + if (typeof temperature !== undefined) { + var percent = (temperature + 60)/120; + var index = Math.min(3, Math.floor(4 * percent)); + res.url = images[index]; + } + return res; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md new file mode 100644 index 0000000000..736bd727f0 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md @@ -0,0 +1,42 @@ +#### Polygon color function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute color of the polygon. + +**Parameters:** + +
      + {% include widget/lib/map/map_fn_args %} +
    + +**Returns:** + +Should return string value presenting color of the polygon. + +In case no data is returned, color value from **Polygon color** settings field will be used. + +
    + +##### Examples + +* Calculate color depending on `temperature` telemetry value for `thermostat` device type: + +```javascript +var type = data['Type']; +if (type == 'thermostat') { + var temperature = data['temperature']; + if (typeof temperature !== undefined) { + var percent = (temperature + 60)/120 * 100; + return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + } + return 'blue'; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_tooltip_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_tooltip_fn.md new file mode 100644 index 0000000000..86de41c185 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_tooltip_fn.md @@ -0,0 +1,40 @@ +#### Polygon tooltip function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute text or HTML code to be displayed in the polygon tooltip. + +**Parameters:** + +
      + {% include widget/lib/map/map_fn_args %} +
    + +**Returns:** + +Should return string value presenting text or HTML for the polygon tooltip. + +
    + +##### Examples + +* Display details with corresponding telemetry data for `energy meter` or `thermostat` device types: + +```javascript +var deviceType = data['Type']; +if (typeof deviceType !== undefined) { + if (deviceType == "energy meter") { + return '${entityName}
    Energy: ${energy:2} kWt
    '; + } else if (deviceType == "thermostat") { + return '${entityName}
    Temperature: ${temperature:2} °C
    '; + } +} +return data.entityName; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/position_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/position_fn.md new file mode 100644 index 0000000000..98821e70a5 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/position_fn.md @@ -0,0 +1,41 @@ +#### Position conversion function + +
    +
    + +*function (origXPos, origYPos): {x: number, y: number}* + +A JavaScript function used to convert original relative x, y coordinates of the marker. + +**Parameters:** + +- **origXPos:** number - original relative x coordinate as double from 0 to 1; +- **origYPos:** number - original relative y coordinate as double from 0 to 1; + +**Returns:** + +Should return position data having the following structure: + +```typescript +{ + x: number, + y: number +} +``` + +- *x* - new relative x coordinate as double from 0 to 1; +- *y* - new relative y coordinate as double from 0 to 1; + +
    + +##### Examples + +* Scale the coordinates to half the original: + +```javascript +return {x: origXPos / 2, y: origYPos / 2}; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/tooltip_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/tooltip_fn.md new file mode 100644 index 0000000000..6468b8a973 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/tooltip_fn.md @@ -0,0 +1,40 @@ +#### Marker tooltip function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute text or HTML code to be displayed in the marker tooltip. + +**Parameters:** + +
      + {% include widget/lib/map/map_fn_args %} +
    + +**Returns:** + +Should return string value presenting text or HTML for the marker tooltip. + +
    + +##### Examples + +* Display details with corresponding telemetry data for `thermostat` device type: + +```javascript +var deviceType = data['Type']; +if (typeof deviceType !== undefined) { + if (deviceType == "energy meter") { + return '${entityName}
    Energy: ${energy:2} kWt
    '; + } else if (deviceType == "thermometer") { + return '${entityName}
    Temperature: ${temperature:2} °C
    '; + } +} +return data.entityName; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_fn_args.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_fn_args.md new file mode 100644 index 0000000000..a6adebddb6 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_fn_args.md @@ -0,0 +1,11 @@ +
  • data: FormattedData - A FormattedData object associated with the point of the trip.
    + Represents basic entity properties (ex. entityId, entityName)
    and provides access to other entity attributes/timeseries declared in widget datasource configuration. +
  • +
  • dsData: FormattedData[][] - two-dimensional array of FormattedData objects presenting
    + array of trips (entities with timeseries data) resolved from configured datasources.
    + Each element of array is particular entity trip data presented as array of FormattedData object (trip point).
    + Each object represents basic entity properties (ex. entityId, entityName)
    + and provides access to other entity attributes/timeseries declared in widget datasource configuration. +
  • +
  • dsIndex number - index of the current trip data in dsData array. +
  • diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_label_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_label_fn.md new file mode 100644 index 0000000000..0203a592f8 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_label_fn.md @@ -0,0 +1,40 @@ +#### Trip animation widget label function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute text or HTML code of the marker label. + +**Parameters:** + +
      + {% include widget/lib/map/trip_fn_args %} +
    + +**Returns:** + +Should return string value presenting text or HTML of the marker label. + +
    + +##### Examples + +* Display styled label with corresponding latest telemetry data for `energy meter` or `thermometer` device types: + +```javascript +var deviceType = data['Type']; +if (typeof deviceType !== undefined) { + if (deviceType == "energy meter") { + return '${entityName}, ${energy:2} kWt'; + } else if (deviceType == "thermometer") { + return '${entityName}, ${temperature:2} °C'; + } +} +return data.entityName; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_marker_image_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_marker_image_fn.md new file mode 100644 index 0000000000..b5389985eb --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_marker_image_fn.md @@ -0,0 +1,62 @@ +#### Marker image function + +
    +
    + +*function (data, images, dsData, dsIndex): {url: string, size: number}* + +A JavaScript function used to compute marker image. + +**Parameters:** + +
      + {% include widget/lib/map/trip_fn_args %} +
    + +**Returns:** + +Should return marker image data having the following structure: + +```typescript +{ + url: string, + size: number +} +``` + +- *url* - marker image url; +- *size* - marker image size; + +In case no data is returned, default marker image will be used. + +
    + +##### Examples + +
      +
    • +Calculate image url depending on temperature telemetry value for thermometer device type.
      +Let's assume 4 images are defined in Marker images section. Each image corresponds to particular temperature level: +
    • +
    + +```javascript +var type = data['Type']; +if (type == 'thermometer') { + var res = { + url: images[0], + size: 40 + } + var temperature = data['temperature']; + if (typeof temperature !== undefined) { + var percent = (temperature + 60)/120; + var index = Math.min(3, Math.floor(4 * percent)); + res.url = images[index]; + } + return res; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_color_fn.md new file mode 100644 index 0000000000..5afcd678c7 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_color_fn.md @@ -0,0 +1,42 @@ +#### Path color function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute color of the trip path. + +**Parameters:** + +
      + {% include widget/lib/map/trip_fn_args %} +
    + +**Returns:** + +Should return string value presenting color of the trip path. + +In case no data is returned, color value from **Path color** settings field will be used. + +
    + +##### Examples + +* Calculate color depending on `temperature` telemetry value for `colorpin` device type: + +```javascript +var type = data['Type']; +if (type == 'colorpin') { + var temperature = data['temperature']; + if (typeof temperature !== undefined) { + var percent = (temperature + 60)/120 * 100; + return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + } + return 'blue'; +} +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_point_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_point_color_fn.md new file mode 100644 index 0000000000..3b16a3ef22 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_point_color_fn.md @@ -0,0 +1,43 @@ +#### Path point color function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute color of the trip path point. + +**Parameters:** + +
      + {% include widget/lib/map/trip_fn_args %} +
    + +**Returns:** + +Should return string value presenting color of the trip path point. + +In case no data is returned, color value from **Point color** settings field will be used. + +
    + +##### Examples + +* Calculate color depending on `temperature` telemetry value for `colorpin` device type: + +```javascript +var type = data['Type']; +if (type == 'colorpin') { + var temperature = data['temperature']; + if (typeof temperature !== undefined) { + var percent = (temperature + 60)/120 * 100; + return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + } + return 'blue'; +} +{:copy-code} +``` + +
    +
    + diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_point_as_anchor_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_point_as_anchor_fn.md new file mode 100644 index 0000000000..788e2bb189 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_point_as_anchor_fn.md @@ -0,0 +1,34 @@ +#### Point as anchor function + +
    +
    + +*function (data, dsData, dsIndex): boolean* + +A JavaScript function evaluating whether to use trip point as time anchor used in time selector. + +**Parameters:** + +
      + {% include widget/lib/map/trip_fn_args %} +
    + +**Returns:** + +`true` if the point should be decided as anchor, `false` otherwise. + +In case no data is returned, the point is not used as anchor. + +
    + +##### Examples + +* Make anchors with 5 seconds step interval: + +```javascript +return data.time % 5000 < 1000; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_tooltip_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_tooltip_fn.md new file mode 100644 index 0000000000..6678dc9b2e --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_tooltip_fn.md @@ -0,0 +1,40 @@ +#### Trip animation widget tooltip function + +
    +
    + +*function (data, dsData, dsIndex): string* + +A JavaScript function used to compute text or HTML code to be displayed in the marker tooltip. + +**Parameters:** + +
      + {% include widget/lib/map/trip_fn_args %} +
    + +**Returns:** + +Should return string value presenting text or HTML for the marker tooltip. + +
    + +##### Examples + +* Display details with corresponding telemetry data for `thermostat` device type: + +```javascript +var deviceType = data['Type']; +if (typeof deviceType !== undefined) { + if (deviceType == "energy meter") { + return '${entityName}
    Energy: ${energy:2} kWt
    '; + } else if (deviceType == "thermometer") { + return '${entityName}
    Temperature: ${temperature:2} °C
    '; + } +} +return data.entityName; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/rpc/convert_value_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/rpc/convert_value_fn.md new file mode 100644 index 0000000000..816fa10263 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/rpc/convert_value_fn.md @@ -0,0 +1,40 @@ +#### Convert value function + +
    +
    + +*function (value): any* + +A JavaScript function converting target on/off state of the control widget to payload of the RPC set value command. + +**Parameters:** + +
      +
    • value: boolean - value indicating target on/off state of the control widget. +
    • +
    + +**Returns:** + +Payload object or primitive to be used by the RPC set value command. + +
    + +##### Examples + +* Use original target value as payload: + +```javascript +return value; +{:copy-code} +``` + +* Create json payload with `enabled` boolean property: + +```javascript +return { enabled: value }; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/rpc/parse_gpio_status_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/rpc/parse_gpio_status_fn.md new file mode 100644 index 0000000000..417283a579 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/rpc/parse_gpio_status_fn.md @@ -0,0 +1,35 @@ +#### Parse GPIO status function + +
    +
    + +*function (body, pin): boolean* + +A JavaScript function evaluating enabled/disable state of GPIO pin from the response of GPIO status request. + +**Parameters:** + +
      +
    • body: any - response body of the GPIO status request. +
    • +
    • pin: number - number of the GPIO pin. +
    • +
    + +**Returns:** + +`true` if GPIO pin should be enabled, `false` otherwise. + +
    + +##### Examples + +* Detect status of the pin assuming response body is array of boolean pins states: + +```javascript +return body[pin] === true; +{:copy-code} +``` + +
    +
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/rpc/parse_value_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/rpc/parse_value_fn.md new file mode 100644 index 0000000000..c2479de798 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/rpc/parse_value_fn.md @@ -0,0 +1,41 @@ +#### Parse value function + +
    +
    + +*function (data): boolean* + +A JavaScript function converting attribute/timeseries value or value of the RPC command response to boolean value. + +**Parameters:** + +
      +
    • data: any - attribute/timeseries value or value of the RPC command response. +
    • +
    + +**Returns:** + +`true` if control widget should be switched on, `false` otherwise. + +
    + +##### Examples + +* Switch on control widget for any positive value: + +```javascript +return data ? true : false; +{:copy-code} +``` + +* Parse control widget state from json payload having `enabled` boolean property: + +```javascript +var payload = typeof data === 'string' ? JSON.parse(data) : data; +return payload && payload.enabled ? true : false; +{:copy-code} +``` + +
    +
    From 1236e89bcac4e5bcf248204e2d5a03ec1852f0aa Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 20 Oct 2021 15:46:23 +0300 Subject: [PATCH 105/303] Queue controller description --- .../server/controller/BaseController.java | 2 ++ .../server/controller/QueueController.java | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 75adfffa61..505896755f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -240,6 +240,8 @@ public abstract class BaseController { protected static final String RELATION_INFO_DESCRIPTION = "Relation Info is an extension of the default Relation object that contains information about the 'from' and 'to' entity names. "; protected static final String EDGE_INFO_DESCRIPTION = "Edge Info is an extension of the default Edge object that contains information about the assigned customer name. "; protected static final String DEVICE_PROFILE_INFO_DESCRIPTION = "Device Profile Info is a lightweight object that includes main information about Device Profile excluding the heavyweight configuration object. "; + protected static final String QUEUE_SERVICE_TYPE_DESCRIPTION = "Service type (implemented only for the TB-RULE-ENGINE)"; + protected static final String QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES = "TB-RULE-ENGINE, TB-CORE, TB-TRANSPORT, JS-EXECUTOR"; protected static final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; protected static final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java index ad3b05d987..d7f59d65ba 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java @@ -15,7 +15,10 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -37,10 +40,13 @@ public class QueueController extends BaseController { private final QueueService queueService; + @ApiOperation(value = "Get queue names (getTenantQueuesByServiceType)", + notes = "Returns a set of unique queue names based on service type. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/tenant/queues", params = {"serviceType"}, method = RequestMethod.GET) - @ResponseBody - public Set getTenantQueuesByServiceType(@RequestParam String serviceType) throws ThingsboardException { + @RequestMapping(value = "/tenant/queues", params = {"serviceType"}, produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + @ResponseBody() + public Set getTenantQueuesByServiceType(@ApiParam(value = QUEUE_SERVICE_TYPE_DESCRIPTION, allowableValues = QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES) + @RequestParam String serviceType) throws ThingsboardException { checkParameter("serviceType", serviceType); try { return queueService.getQueuesByServiceType(ServiceType.valueOf(serviceType)); From 3103f596d58e3ea38a9f348c64061a57e3cb98c4 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 20 Oct 2021 19:29:09 +0300 Subject: [PATCH 106/303] Ota package controller description --- .../server/controller/BaseController.java | 6 ++ .../controller/OtaPackageController.java | 85 +++++++++++++++---- .../server/common/data/OtaPackage.java | 4 + .../server/common/data/OtaPackageInfo.java | 43 +++++++++- .../data/SaveOtaPackageInfoRequest.java | 6 +- 5 files changed, 125 insertions(+), 19 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 505896755f..018b104064 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -177,6 +177,7 @@ public abstract class BaseController { public static final String ASSET_ID_PARAM_DESCRIPTION = "A string value representing the asset id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String ALARM_ID_PARAM_DESCRIPTION = "A string value representing the alarm id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String ENTITY_ID_PARAM_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String OTA_PACKAGE_ID_PARAM_DESCRIPTION = "A string value representing the ota package id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; @@ -242,6 +243,11 @@ public abstract class BaseController { protected static final String DEVICE_PROFILE_INFO_DESCRIPTION = "Device Profile Info is a lightweight object that includes main information about Device Profile excluding the heavyweight configuration object. "; protected static final String QUEUE_SERVICE_TYPE_DESCRIPTION = "Service type (implemented only for the TB-RULE-ENGINE)"; protected static final String QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES = "TB-RULE-ENGINE, TB-CORE, TB-TRANSPORT, JS-EXECUTOR"; + protected static final String OTA_PACKAGE_INFO_DESCRIPTION = "OTA Package Info is a lightweight object that includes main information about the OTA Package excluding the heavyweight data. "; + protected static final String OTA_PACKAGE_DESCRIPTION = "OTA Package is a heavyweight object that includes main information about the OTA Package and also data. "; + protected static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES = "MD5, SHA256, SHA384, SHA512, CRC32, MURMUR3_32, MURMUR3_128"; + protected static final String OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the ota package title."; + protected static final String OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, type, title, version, tag, url, fileName, dataSize, checksum"; protected static final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; protected static final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; diff --git a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java index 4c0a55da70..76ca284e53 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java +++ b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.core.io.ByteArrayResource; @@ -56,10 +58,12 @@ public class OtaPackageController extends BaseController { public static final String OTA_PACKAGE_ID = "otaPackageId"; public static final String CHECKSUM_ALGORITHM = "checksumAlgorithm"; + @ApiOperation(value = "Download OTA Package (downloadOtaPackage)", notes = "Download OTA Package based on the provided OTA Package Id." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')") @RequestMapping(value = "/otaPackage/{otaPackageId}/download", method = RequestMethod.GET) @ResponseBody - public ResponseEntity downloadOtaPackage(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { + public ResponseEntity downloadOtaPackage(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION) + @PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { checkParameter(OTA_PACKAGE_ID, strOtaPackageId); try { OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); @@ -81,10 +85,15 @@ public class OtaPackageController extends BaseController { } } + @ApiOperation(value = "Get OTA Package Info (getOtaPackageInfoById)", + notes = "Fetch the OTA Package Info object based on the provided OTA Package Id. " + + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/otaPackage/info/{otaPackageId}", method = RequestMethod.GET) @ResponseBody - public OtaPackageInfo getOtaPackageInfoById(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { + public OtaPackageInfo getOtaPackageInfoById(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION) + @PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { checkParameter(OTA_PACKAGE_ID, strOtaPackageId); try { OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); @@ -94,10 +103,15 @@ public class OtaPackageController extends BaseController { } } + @ApiOperation(value = "Get OTA Package (getOtaPackageById)", + notes = "Fetch the OTA Package object based on the provided OTA Package Id. " + + "The server checks that the OTA Package is owned by the same tenant. " + OTA_PACKAGE_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.GET) @ResponseBody - public OtaPackage getOtaPackageById(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { + public OtaPackage getOtaPackageById(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION) + @PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { checkParameter(OTA_PACKAGE_ID, strOtaPackageId); try { OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); @@ -107,10 +121,19 @@ public class OtaPackageController extends BaseController { } } + @ApiOperation(value = "Create Or Update OTA Package Info (saveOtaPackageInfo)", + notes = "Create or update the OTA Package Info. When creating OTA Package Info, platform generates OTA Package id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created OTA Package id will be present in the response. " + + "Specify existing OTA Package id to update the OTA Package Info. " + + "Referencing non-existing OTA Package Id will cause 'Not Found' error. " + + "\n\nOTA Package combination of the title with the version is unique in the scope of tenant. " + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json", + consumes = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/otaPackage", method = RequestMethod.POST) @ResponseBody - public OtaPackageInfo saveOtaPackageInfo(@RequestBody SaveOtaPackageInfoRequest otaPackageInfo) throws ThingsboardException { + public OtaPackageInfo saveOtaPackageInfo(@ApiParam(value = "A JSON value representing the OTA Package.") + @RequestBody SaveOtaPackageInfoRequest otaPackageInfo) throws ThingsboardException { boolean created = otaPackageInfo.getId() == null; try { otaPackageInfo.setTenantId(getTenantId()); @@ -126,13 +149,20 @@ public class OtaPackageController extends BaseController { } } + @ApiOperation(value = "Save OTA Package data (saveOtaPackageData)", + notes = "Update the OTA Package. Adds the date to the existing OTA Package Info" + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.POST) @ResponseBody - public OtaPackageInfo saveOtaPackageData(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId, - @RequestParam(required = false) String checksum, - @RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr, - @RequestBody MultipartFile file) throws ThingsboardException { + public OtaPackageInfo saveOtaPackageData(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION) + @PathVariable(OTA_PACKAGE_ID) String strOtaPackageId, + @ApiParam(value = "OTA Package checksum. For example, '0xd87f7e0c'") + @RequestParam(required = false) String checksum, + @ApiParam(value = "OTA Package checksum algorithm.", allowableValues = OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES) + @RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr, + @ApiParam(value = "OTA Package data.") + @RequestBody MultipartFile file) throws ThingsboardException { checkParameter(OTA_PACKAGE_ID, strOtaPackageId); checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr); try { @@ -171,14 +201,23 @@ public class OtaPackageController extends BaseController { } } + @ApiOperation(value = "Get OTA Package Infos (getOtaPackages)", + notes = "Returns a page of OTA Package Info objects owned by tenant. " + + PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/otaPackages", method = RequestMethod.GET) @ResponseBody - public PageData getOtaPackages(@RequestParam int pageSize, - @RequestParam int page, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + public PageData getOtaPackages(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantId(getTenantId(), pageLink)); @@ -187,15 +226,26 @@ public class OtaPackageController extends BaseController { } } + @ApiOperation(value = "Get OTA Package Infos (getOtaPackages)", + notes = "Returns a page of OTA Package Info objects owned by tenant. " + + PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/otaPackages/{deviceProfileId}/{type}", method = RequestMethod.GET) @ResponseBody - public PageData getOtaPackages(@PathVariable("deviceProfileId") String strDeviceProfileId, + public PageData getOtaPackages(@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION) + @PathVariable("deviceProfileId") String strDeviceProfileId, + @ApiParam(value = "OTA Package type.", allowableValues = "FIRMWARE, SOFTWARE") @PathVariable("type") String strType, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("deviceProfileId", strDeviceProfileId); checkParameter("type", strType); @@ -208,10 +258,15 @@ public class OtaPackageController extends BaseController { } } + @ApiOperation(value = "Delete OTA Package (deleteOtaPackage)", + notes = "Deletes the OTA Package. Referencing non-existing OTA Package Id will cause an error. " + + "Can't delete the OTA Package if it is referenced by existing devices or device profile." + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.DELETE) @ResponseBody - public void deleteOtaPackage(@PathVariable("otaPackageId") String strOtaPackageId) throws ThingsboardException { + public void deleteOtaPackage(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION) + @PathVariable("otaPackageId") String strOtaPackageId) throws ThingsboardException { checkParameter(OTA_PACKAGE_ID, strOtaPackageId); try { OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java index 3506aaea75..e60bb69ed9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java @@ -15,18 +15,22 @@ */ package org.thingsboard.server.common.data; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.OtaPackageId; import java.nio.ByteBuffer; +@ApiModel @Data @EqualsAndHashCode(callSuper = true) public class OtaPackage extends OtaPackageInfo { private static final long serialVersionUID = 3091601761339422546L; + @ApiModelProperty(position = 16, value = "OTA Package data.", readOnly = true) private transient ByteBuffer data; public OtaPackage() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java index d50aa70dcb..25feeef682 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java @@ -16,15 +16,19 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; -import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; +import org.thingsboard.server.common.data.ota.OtaPackageType; +@ApiModel @Slf4j @Data @EqualsAndHashCode(callSuper = true) @@ -32,21 +36,33 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo Date: Thu, 21 Oct 2021 12:11:36 +0300 Subject: [PATCH 107/303] Resource controller description --- .../server/controller/BaseController.java | 7 ++ .../controller/TbResourceController.java | 67 ++++++++++++++++--- .../server/common/data/TbResource.java | 3 + .../server/common/data/TbResourceInfo.java | 23 +++++++ .../common/data/lwm2m/LwM2mInstance.java | 5 ++ .../server/common/data/lwm2m/LwM2mObject.java | 9 +++ .../data/lwm2m/LwM2mResourceObserve.java | 9 +++ 7 files changed, 115 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 018b104064..4548551937 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -182,6 +182,7 @@ public abstract class BaseController { public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; public static final String WIDGET_TYPE_ID_PARAM_DESCRIPTION = "A string value representing the widget type id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + public static final String RESOURCE_ID_PARAM_DESCRIPTION = "A string value representing the resource id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; @@ -248,6 +249,12 @@ public abstract class BaseController { protected static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES = "MD5, SHA256, SHA384, SHA512, CRC32, MURMUR3_32, MURMUR3_128"; protected static final String OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the ota package title."; protected static final String OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, type, title, version, tag, url, fileName, dataSize, checksum"; + protected static final String RESOURCE_INFO_DESCRIPTION = "Resource Info is a lightweight object that includes main information about the Resource excluding the heavyweight data. "; + protected static final String RESOURCE_DESCRIPTION = "Resource is a heavyweight object that includes main information about the Resource and also data. "; + protected static final String RESOURCE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the resource title."; + protected static final String RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, resourceType, tenantId"; + protected static final String LWM2M_OBJECT_DESCRIPTION = "LwM2M Object is a object that includes information about the LwM2M model which can be used in transport configuration for the LwM2M device profile. "; + protected static final String LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; protected static final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; protected static final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; diff --git a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java index 97020ca85d..16892fd400 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.ByteArrayResource; import org.springframework.http.HttpHeaders; @@ -53,10 +55,12 @@ public class TbResourceController extends BaseController { public static final String RESOURCE_ID = "resourceId"; + @ApiOperation(value = "Download Resource (downloadResource)", notes = "Download Resource based on the provided Resource Id." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/resource/{resourceId}/download", method = RequestMethod.GET) @ResponseBody - public ResponseEntity downloadResource(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException { + public ResponseEntity downloadResource(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION) + @PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException { checkParameter(RESOURCE_ID, strResourceId); try { TbResourceId resourceId = new TbResourceId(toUUID(strResourceId)); @@ -74,10 +78,15 @@ public class TbResourceController extends BaseController { } } + @ApiOperation(value = "Get Resource Info (getResourceInfoById)", + notes = "Fetch the Resource Info object based on the provided Resource Id. " + + RESOURCE_INFO_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/resource/info/{resourceId}", method = RequestMethod.GET) @ResponseBody - public TbResourceInfo getResourceInfoById(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException { + public TbResourceInfo getResourceInfoById(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION) + @PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException { checkParameter(RESOURCE_ID, strResourceId); try { TbResourceId resourceId = new TbResourceId(toUUID(strResourceId)); @@ -87,10 +96,15 @@ public class TbResourceController extends BaseController { } } + @ApiOperation(value = "Get Resource (getResourceById)", + notes = "Fetch the Resource object based on the provided Resource Id. " + + RESOURCE_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.GET) @ResponseBody - public TbResource getResourceById(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException { + public TbResource getResourceById(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION) + @PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException { checkParameter(RESOURCE_ID, strResourceId); try { TbResourceId resourceId = new TbResourceId(toUUID(strResourceId)); @@ -100,10 +114,19 @@ public class TbResourceController extends BaseController { } } + @ApiOperation(value = "Create Or Update Resource (saveResource)", + notes = "Create or update the Resource. When creating the Resource, platform generates Resource id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "The newly created Resource id will be present in the response. " + + "Specify existing Resource id to update the Resource. " + + "Referencing non-existing Resource Id will cause 'Not Found' error. " + + "\n\nResource combination of the title with the key is unique in the scope of tenant. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json", + consumes = "application/json") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/resource", method = RequestMethod.POST) @ResponseBody - public TbResource saveResource(@RequestBody TbResource resource) throws ThingsboardException { + public TbResource saveResource(@ApiParam(value = "A JSON value representing the Resource.") + @RequestBody TbResource resource) throws ThingsboardException { boolean created = resource.getId() == null; try { resource.setTenantId(getTenantId()); @@ -120,13 +143,22 @@ public class TbResourceController extends BaseController { } } + @ApiOperation(value = "Get Resource Infos (getResources)", + notes = "Returns a page of Resource Info objects owned by tenant or sysadmin. " + + PAGE_DATA_PARAMETERS + RESOURCE_INFO_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/resource", method = RequestMethod.GET) @ResponseBody - public PageData getResources(@RequestParam int pageSize, + public PageData getResources(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = RESOURCE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); @@ -140,13 +172,22 @@ public class TbResourceController extends BaseController { } } + @ApiOperation(value = "Get LwM2M Objects (getLwm2mListObjectsPage)", + notes = "Returns a page of LwM2M objects parsed from Resources with type 'LWM2M_MODEL' owned by tenant or sysadmin. " + + PAGE_DATA_PARAMETERS + LWM2M_OBJECT_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/resource/lwm2m/page", method = RequestMethod.GET) @ResponseBody - public List getLwm2mListObjectsPage(@RequestParam int pageSize, + public List getLwm2mListObjectsPage(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = RESOURCE_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { PageLink pageLink = new PageLink(pageSize, page, textSearch); @@ -156,11 +197,18 @@ public class TbResourceController extends BaseController { } } + @ApiOperation(value = "Get LwM2M Objects (getLwm2mListObjects)", + notes = "Returns a page of LwM2M objects parsed from Resources with type 'LWM2M_MODEL' owned by tenant or sysadmin. " + + "You can specify parameters to filter the results. " + LWM2M_OBJECT_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/resource/lwm2m", method = RequestMethod.GET) @ResponseBody - public List getLwm2mListObjects(@RequestParam String sortOrder, + public List getLwm2mListObjects(@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES, required = true) + @RequestParam String sortOrder, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES, required = true) @RequestParam String sortProperty, + @ApiParam(value = "LwM2M Object ids.", required = true) @RequestParam(required = false) String[] objectIds) throws ThingsboardException { try { return checkNotNull(resourceService.findLwM2mObject(getTenantId(), sortOrder, sortProperty, objectIds)); @@ -169,10 +217,13 @@ public class TbResourceController extends BaseController { } } + @ApiOperation(value = "Delete Resource (deleteResource)", + notes = "Deletes the Resource. Referencing non-existing Resource Id will cause an error." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.DELETE) @ResponseBody - public void deleteResource(@PathVariable("resourceId") String strResourceId) throws ThingsboardException { + public void deleteResource(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION) + @PathVariable("resourceId") String strResourceId) throws ThingsboardException { checkParameter(RESOURCE_ID, strResourceId); try { TbResourceId resourceId = new TbResourceId(toUUID(strResourceId)); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java b/common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java index 28c7e73e26..569b42d366 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -29,8 +30,10 @@ public class TbResource extends TbResourceInfo { private static final long serialVersionUID = 7379609705527272306L; @NoXss + @ApiModelProperty(position = 8, value = "Resource file name.", example = "19.xml", readOnly = true) private String fileName; + @ApiModelProperty(position = 9, value = "Resource data.", example = "77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLQpGSUxFIElORk9STUFUSU9OCgpPTUEgUGVybWFuZW50IERvY3VtZW50CiAgIEZpbGU6IE9NQS1TVVAtTHdNMk1fQmluYXJ5QXBwRGF0YUNvbnRhaW5lci1WMV8wXzEtMjAxOTAyMjEtQQogICBUeXBlOiB4bWwKClB1YmxpYyBSZWFjaGFibGUgSW5mb3JtYXRpb24KICAgUGF0aDogaHR0cDovL3d3dy5vcGVubW9iaWxlYWxsaWFuY2Uub3JnL3RlY2gvcHJvZmlsZXMKICAgTmFtZTogTHdNMk1fQmluYXJ5QXBwRGF0YUNvbnRhaW5lci12MV8wXzEueG1sCgpOT1JNQVRJVkUgSU5GT1JNQVRJT04KCiAgSW5mb3JtYXRpb24gYWJvdXQgdGhpcyBmaWxlIGNhbiBiZSBmb3VuZCBpbiB0aGUgbGF0ZXN0IHJldmlzaW9uIG9mCgogIE9NQS1UUy1MV00yTV9CaW5hcnlBcHBEYXRhQ29udGFpbmVyLVYxXzBfMQoKICBUaGlzIGlzIGF2YWlsYWJsZSBhdCBodHRwOi8vd3d3Lm9wZW5tb2JpbGVhbGxpYW5jZS5vcmcvCgogIFNlbmQgY29tbWVudHMgdG8gaHR0cHM6Ly9naXRodWIuY29tL09wZW5Nb2JpbGVBbGxpYW5jZS9PTUFfTHdNMk1fZm9yX0RldmVsb3BlcnMvaXNzdWVzCgpDSEFOR0UgSElTVE9SWQoKMTUwNjIwMTggU3RhdHVzIGNoYW5nZWQgdG8gQXBwcm92ZWQgYnkgRE0sIERvYyBSZWYgIyBPTUEtRE0mU0UtMjAxOC0wMDYxLUlOUF9MV00yTV9BUFBEQVRBX1YxXzBfRVJQX2Zvcl9maW5hbF9BcHByb3ZhbAoyMTAyMjAxOSBTdGF0dXMgY2hhbmdlZCB0byBBcHByb3ZlZCBieSBJUFNPLCBEb2MgUmVmICMgT01BLUlQU08tMjAxOS0wMDI1LUlOUF9Md00yTV9PYmplY3RfQXBwX0RhdGFfQ29udGFpbmVyXzFfMF8xX2Zvcl9GaW5hbF9BcHByb3ZhbAoKTEVHQUwgRElTQ0xBSU1FUgoKQ29weXJpZ2h0IDIwMTkgT3BlbiBNb2JpbGUgQWxsaWFuY2UuCgpSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKbW9kaWZpY2F0aW9uLCBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zCmFyZSBtZXQ6CgoxLiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodApub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCjIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0Cm5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lciBpbiB0aGUKZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4KMy4gTmVpdGhlciB0aGUgbmFtZSBvZiB0aGUgY29weXJpZ2h0IGhvbGRlciBub3IgdGhlIG5hbWVzIG9mIGl0cwpjb250cmlidXRvcnMgbWF5IGJlIHVzZWQgdG8gZW5kb3JzZSBvciBwcm9tb3RlIHByb2R1Y3RzIGRlcml2ZWQKZnJvbSB0aGlzIHNvZnR3YXJlIHdpdGhvdXQgc3BlY2lmaWMgcHJpb3Igd3JpdHRlbiBwZXJtaXNzaW9uLgoKVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRSSUJVVE9SUwoiQVMgSVMiIEFORCBBTlkgRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVApMSU1JVEVEIFRPLCBUSEUgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUwpGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRQpDT1BZUklHSFQgSE9MREVSIE9SIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsIElORElSRUNULApJTkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyAoSU5DTFVESU5HLApCVVQgTk9UIExJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVM7CkxPU1MgT0YgVVNFLCBEQVRBLCBPUiBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIKQ0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUCkxJQUJJTElUWSwgT1IgVE9SVCAoSU5DTFVESU5HIE5FR0xJR0VOQ0UgT1IgT1RIRVJXSVNFKSBBUklTSU5HIElOCkFOWSBXQVkgT1VUIE9GIFRIRSBVU0UgT0YgVEhJUyBTT0ZUV0FSRSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRQpQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS4KClRoZSBhYm92ZSBsaWNlbnNlIGlzIHVzZWQgYXMgYSBsaWNlbnNlIHVuZGVyIGNvcHlyaWdodCBvbmx5LiBQbGVhc2UKcmVmZXJlbmNlIHRoZSBPTUEgSVBSIFBvbGljeSBmb3IgcGF0ZW50IGxpY2Vuc2luZyB0ZXJtczoKaHR0cHM6Ly93d3cub21hc3BlY3dvcmtzLm9yZy9hYm91dC9pbnRlbGxlY3R1YWwtcHJvcGVydHktcmlnaHRzLwoKLS0+CjxMV00yTSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6bm9OYW1lc3BhY2VTY2hlbWFMb2NhdGlvbj0iaHR0cDovL29wZW5tb2JpbGVhbGxpYW5jZS5vcmcvdGVjaC9wcm9maWxlcy9MV00yTS54c2QiPgoJPE9iamVjdCBPYmplY3RUeXBlPSJNT0RlZmluaXRpb24iPgoJCTxOYW1lPkJpbmFyeUFwcERhdGFDb250YWluZXI8L05hbWU+CgkJPERlc2NyaXB0aW9uMT48IVtDREFUQVtUaGlzIEx3TTJNIE9iamVjdHMgcHJvdmlkZXMgdGhlIGFwcGxpY2F0aW9uIHNlcnZpY2UgZGF0YSByZWxhdGVkIHRvIGEgTHdNMk0gU2VydmVyLCBlZy4gV2F0ZXIgbWV0ZXIgZGF0YS4gClRoZXJlIGFyZSBzZXZlcmFsIG1ldGhvZHMgdG8gY3JlYXRlIGluc3RhbmNlIHRvIGluZGljYXRlIHRoZSBtZXNzYWdlIGRpcmVjdGlvbiBiYXNlZCBvbiB0aGUgbmVnb3RpYXRpb24gYmV0d2VlbiBBcHBsaWNhdGlvbiBhbmQgTHdNMk0uIFRoZSBDbGllbnQgYW5kIFNlcnZlciBzaG91bGQgbmVnb3RpYXRlIHRoZSBpbnN0YW5jZShzKSB1c2VkIHRvIGV4Y2hhbmdlIHRoZSBkYXRhLiBGb3IgZXhhbXBsZToKIC0gVXNpbmcgYSBzaW5nbGUgaW5zdGFuY2UgZm9yIGJvdGggZGlyZWN0aW9ucyBjb21tdW5pY2F0aW9uLCBmcm9tIENsaWVudCB0byBTZXJ2ZXIgYW5kIGZyb20gU2VydmVyIHRvIENsaWVudC4KIC0gVXNpbmcgYW4gaW5zdGFuY2UgZm9yIGNvbW11bmljYXRpb24gZnJvbSBDbGllbnQgdG8gU2VydmVyIGFuZCBhbm90aGVyIG9uZSBmb3IgY29tbXVuaWNhdGlvbiBmcm9tIFNlcnZlciB0byBDbGllbnQKIC0gVXNpbmcgc2V2ZXJhbCBpbnN0YW5jZXMKXV0+PC9EZXNjcmlwdGlvbjE+CgkJPE9iamVjdElEPjE5PC9PYmplY3RJRD4KCQk8T2JqZWN0VVJOPnVybjpvbWE6bHdtMm06b21hOjE5PC9PYmplY3RVUk4+CgkJPExXTTJNVmVyc2lvbj4xLjA8L0xXTTJNVmVyc2lvbj4KCQk8T2JqZWN0VmVyc2lvbj4xLjA8L09iamVjdFZlcnNpb24+CgkJPE11bHRpcGxlSW5zdGFuY2VzPk11bHRpcGxlPC9NdWx0aXBsZUluc3RhbmNlcz4KCQk8TWFuZGF0b3J5Pk9wdGlvbmFsPC9NYW5kYXRvcnk+CgkJPFJlc291cmNlcz4KCQkJPEl0ZW0gSUQ9IjAiPjxOYW1lPkRhdGE8L05hbWU+CgkJCQk8T3BlcmF0aW9ucz5SVzwvT3BlcmF0aW9ucz4KCQkJCTxNdWx0aXBsZUluc3RhbmNlcz5NdWx0aXBsZTwvTXVsdGlwbGVJbnN0YW5jZXM+CgkJCQk8TWFuZGF0b3J5Pk1hbmRhdG9yeTwvTWFuZGF0b3J5PgoJCQkJPFR5cGU+T3BhcXVlPC9UeXBlPgoJCQkJPFJhbmdlRW51bWVyYXRpb24gLz4KCQkJCTxVbml0cyAvPgoJCQkJPERlc2NyaXB0aW9uPjwhW0NEQVRBW0luZGljYXRlcyB0aGUgYXBwbGljYXRpb24gZGF0YSBjb250ZW50Ll1dPjwvRGVzY3JpcHRpb24+CgkJCTwvSXRlbT4KCQkJPEl0ZW0gSUQ9IjEiPjxOYW1lPkRhdGEgUHJpb3JpdHk8L05hbWU+CgkJCQk8T3BlcmF0aW9ucz5SVzwvT3BlcmF0aW9ucz4KCQkJCTxNdWx0aXBsZUluc3RhbmNlcz5TaW5nbGU8L011bHRpcGxlSW5zdGFuY2VzPgoJCQkJPE1hbmRhdG9yeT5PcHRpb25hbDwvTWFuZGF0b3J5PgoJCQkJPFR5cGU+SW50ZWdlcjwvVHlwZT4KCQkJCTxSYW5nZUVudW1lcmF0aW9uPjEgYnl0ZXM8L1JhbmdlRW51bWVyYXRpb24+CgkJCQk8VW5pdHMgLz4KCQkJCTxEZXNjcmlwdGlvbj48IVtDREFUQVtJbmRpY2F0ZXMgdGhlIEFwcGxpY2F0aW9uIGRhdGEgcHJpb3JpdHk6CjA6SW1tZWRpYXRlCjE6QmVzdEVmZm9ydAoyOkxhdGVzdAozLTEwMDogUmVzZXJ2ZWQgZm9yIGZ1dHVyZSB1c2UuCjEwMS0yNTQ6IFByb3ByaWV0YXJ5IG1vZGUuXV0+PC9EZXNjcmlwdGlvbj4KCQkJPC9JdGVtPgoJCQk8SXRlbSBJRD0iMiI+PE5hbWU+RGF0YSBDcmVhdGlvbiBUaW1lPC9OYW1lPgoJCQkJPE9wZXJhdGlvbnM+Ulc8L09wZXJhdGlvbnM+CgkJCQk8TXVsdGlwbGVJbnN0YW5jZXM+U2luZ2xlPC9NdWx0aXBsZUluc3RhbmNlcz4KCQkJCTxNYW5kYXRvcnk+T3B0aW9uYWw8L01hbmRhdG9yeT4KCQkJCTxUeXBlPlRpbWU8L1R5cGU+CgkJCQk8UmFuZ2VFbnVtZXJhdGlvbiAvPgoJCQkJPFVuaXRzIC8+CgkJCQk8RGVzY3JpcHRpb24+PCFbQ0RBVEFbSW5kaWNhdGVzIHRoZSBEYXRhIGluc3RhbmNlIGNyZWF0aW9uIHRpbWVzdGFtcC5dXT48L0Rlc2NyaXB0aW9uPgoJCQk8L0l0ZW0+CgkJCTxJdGVtIElEPSIzIj48TmFtZT5EYXRhIERlc2NyaXB0aW9uPC9OYW1lPgoJCQkJPE9wZXJhdGlvbnM+Ulc8L09wZXJhdGlvbnM+CgkJCQk8TXVsdGlwbGVJbnN0YW5jZXM+U2luZ2xlPC9NdWx0aXBsZUluc3RhbmNlcz4KCQkJCTxNYW5kYXRvcnk+T3B0aW9uYWw8L01hbmRhdG9yeT4KCQkJCTxUeXBlPlN0cmluZzwvVHlwZT4KCQkJCTxSYW5nZUVudW1lcmF0aW9uPjMyIGJ5dGVzPC9SYW5nZUVudW1lcmF0aW9uPgoJCQkJPFVuaXRzIC8+CgkJCQk8RGVzY3JpcHRpb24+PCFbQ0RBVEFbSW5kaWNhdGVzIHRoZSBkYXRhIGRlc2NyaXB0aW9uLgplLmcuICJtZXRlciByZWFkaW5nIi5dXT48L0Rlc2NyaXB0aW9uPgoJCQk8L0l0ZW0+CgkJCTxJdGVtIElEPSI0Ij48TmFtZT5EYXRhIEZvcm1hdDwvTmFtZT4KCQkJCTxPcGVyYXRpb25zPlJXPC9PcGVyYXRpb25zPgoJCQkJPE11bHRpcGxlSW5zdGFuY2VzPlNpbmdsZTwvTXVsdGlwbGVJbnN0YW5jZXM+CgkJCQk8TWFuZGF0b3J5Pk9wdGlvbmFsPC9NYW5kYXRvcnk+CgkJCQk8VHlwZT5TdHJpbmc8L1R5cGU+CgkJCQk8UmFuZ2VFbnVtZXJhdGlvbj4zMiBieXRlczwvUmFuZ2VFbnVtZXJhdGlvbj4KCQkJCTxVbml0cyAvPgoJCQkJPERlc2NyaXB0aW9uPjwhW0NEQVRBW0luZGljYXRlcyB0aGUgZm9ybWF0IG9mIHRoZSBBcHBsaWNhdGlvbiBEYXRhLgplLmcuIFlHLU1ldGVyLVdhdGVyLVJlYWRpbmcKVVRGOC1zdHJpbmcKXV0+PC9EZXNjcmlwdGlvbj4KCQkJPC9JdGVtPgoJCQk8SXRlbSBJRD0iNSI+PE5hbWU+QXBwIElEPC9OYW1lPgoJCQkJPE9wZXJhdGlvbnM+Ulc8L09wZXJhdGlvbnM+CgkJCQk8TXVsdGlwbGVJbnN0YW5jZXM+U2luZ2xlPC9NdWx0aXBsZUluc3RhbmNlcz4KCQkJCTxNYW5kYXRvcnk+T3B0aW9uYWw8L01hbmRhdG9yeT4KCQkJCTxUeXBlPkludGVnZXI8L1R5cGU+CgkJCQk8UmFuZ2VFbnVtZXJhdGlvbj4yIGJ5dGVzPC9SYW5nZUVudW1lcmF0aW9uPgoJCQkJPFVuaXRzIC8+CgkJCQk8RGVzY3JpcHRpb24+PCFbQ0RBVEFbSW5kaWNhdGVzIHRoZSBkZXN0aW5hdGlvbiBBcHBsaWNhdGlvbiBJRC5dXT48L0Rlc2NyaXB0aW9uPgoJCQk8L0l0ZW0+PC9SZXNvdXJjZXM+CgkJPERlc2NyaXB0aW9uMj48IVtDREFUQVtdXT48L0Rlc2NyaXB0aW9uMj4KCTwvT2JqZWN0Pgo8L0xXTTJNPgo=", readOnly = true) private String data; public TbResource() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java index 9d72d01534..1c4529cd36 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java @@ -16,6 +16,8 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -23,6 +25,7 @@ import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.validation.NoXss; +@ApiModel @Slf4j @Data @EqualsAndHashCode(callSuper = true) @@ -30,11 +33,16 @@ public class TbResourceInfo extends SearchTextBased implements Has private static final long serialVersionUID = 7282664529021651736L; + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Tenant Id of the resource can't be changed.", readOnly = true) private TenantId tenantId; @NoXss + @ApiModelProperty(position = 4, value = "Resource title.", example = "BinaryAppDataContainer id=19 v1.0") private String title; + @ApiModelProperty(position = 5, value = "Resource type.", example = "LWM2M_MODEL", readOnly = true) private ResourceType resourceType; + @ApiModelProperty(position = 6, value = "Resource key.", example = "19_1.0", readOnly = true) private String resourceKey; + @ApiModelProperty(position = 7, value = "Resource search text.", example = "19_1.0:binaryappdatacontainer", readOnly = true) private String searchText; public TbResourceInfo() { @@ -54,6 +62,21 @@ public class TbResourceInfo extends SearchTextBased implements Has this.searchText = resourceInfo.getSearchText(); } + @ApiModelProperty(position = 1, value = "JSON object with the Resource Id. " + + "Specify this field to update the Resource. " + + "Referencing non-existing Resource Id will cause error. " + + "Omit this field to create new Resource." ) + @Override + public TbResourceId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the resource creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + @Override @JsonIgnore public String getName() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java index 1e0ff70e8a..7f9149e31e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java @@ -15,11 +15,16 @@ */ package org.thingsboard.server.common.data.lwm2m; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; +@ApiModel @Data public class LwM2mInstance { + @ApiModelProperty(position = 1, value = "LwM2M Instance id.", example = "0") int id; + @ApiModelProperty(position = 2, value = "LwM2M Resource observe.") LwM2mResourceObserve[] resources; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java index 80174b430f..c7ed3c5a2c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java @@ -15,14 +15,23 @@ */ package org.thingsboard.server.common.data.lwm2m; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; +@ApiModel @Data public class LwM2mObject { + @ApiModelProperty(position = 1, value = "LwM2M Object id.", example = "19") int id; + @ApiModelProperty(position = 2, value = "LwM2M Object key id.", example = "19_1.0") String keyId; + @ApiModelProperty(position = 3, value = "LwM2M Object name.", example = "BinaryAppDataContainer") String name; + @ApiModelProperty(position = 4, value = "LwM2M Object multiple.", example = "true") boolean multiple; + @ApiModelProperty(position = 5, value = "LwM2M Object mandatory.", example = "false") boolean mandatory; + @ApiModelProperty(position = 6, value = "LwM2M Object instances.") LwM2mInstance [] instances; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResourceObserve.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResourceObserve.java index 402309ebf3..86f5c16540 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResourceObserve.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResourceObserve.java @@ -15,19 +15,28 @@ */ package org.thingsboard.server.common.data.lwm2m; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import java.util.stream.Stream; +@ApiModel @Data @AllArgsConstructor public class LwM2mResourceObserve { + @ApiModelProperty(position = 1, value = "LwM2M Resource Observe id.", example = "0") int id; + @ApiModelProperty(position = 2, value = "LwM2M Resource Observe name.", example = "Data") String name; + @ApiModelProperty(position = 3, value = "LwM2M Resource Observe observe.", example = "false") boolean observe; + @ApiModelProperty(position = 4, value = "LwM2M Resource Observe attribute.", example = "false") boolean attribute; + @ApiModelProperty(position = 5, value = "LwM2M Resource Observe telemetry.", example = "false") boolean telemetry; + @ApiModelProperty(position = 6, value = "LwM2M Resource Observe key name.", example = "data") String keyName; public LwM2mResourceObserve(int id, String name, boolean observe, boolean attribute, boolean telemetry) { From 62e17ffd48ee3ef75d844174312f2c708dea5fbc Mon Sep 17 00:00:00 2001 From: Ekaterina Chantsova Date: Thu, 21 Oct 2021 13:10:31 +0300 Subject: [PATCH 108/303] Save translated title as variable --- .../dashboard-page/dashboard-page.component.html | 2 +- .../dashboard-page/dashboard-page.component.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 8f97f5c7e8..27c436c802 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -148,7 +148,7 @@
    -

    {{ utils.customTranslation(dashboard.title, dashboard.title) }}

    +

    {{ translatedDashboardTitle }}

    dashboard.title Date: Thu, 21 Oct 2021 15:43:15 +0300 Subject: [PATCH 109/303] Fixed map functions. Update map helps. --- ui-ngx/src/app/core/api/data-aggregator.ts | 30 ++++++--- .../widget/lib/maps/common-maps-utils.ts | 55 +++++++++------- .../components/widget/lib/maps/leaflet-map.ts | 60 ++++++++++-------- .../components/widget/lib/maps/schemes.ts | 10 +-- .../trip-animation.component.html | 4 +- .../trip-animation.component.ts | 43 +++++++------ .../help/en_US/widget/lib/map/map_fn_args.md | 6 +- ...trip_path_color_fn.md => path_color_fn.md} | 2 +- ...int_color_fn.md => path_point_color_fn.md} | 2 +- .../help/en_US/widget/lib/map/tooltip_fn.md | 4 +- .../help/en_US/widget/lib/map/trip_fn_args.md | 11 ---- .../en_US/widget/lib/map/trip_label_fn.md | 40 ------------ .../widget/lib/map/trip_marker_image_fn.md | 62 ------------------- .../widget/lib/map/trip_point_as_anchor_fn.md | 2 +- .../en_US/widget/lib/map/trip_tooltip_fn.md | 40 ------------ 15 files changed, 126 insertions(+), 245 deletions(-) rename ui-ngx/src/assets/help/en_US/widget/lib/map/{trip_path_color_fn.md => path_color_fn.md} (94%) rename ui-ngx/src/assets/help/en_US/widget/lib/map/{trip_path_point_color_fn.md => path_point_color_fn.md} (95%) delete mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_fn_args.md delete mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_label_fn.md delete mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_marker_image_fn.md delete mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/map/trip_tooltip_fn.md diff --git a/ui-ngx/src/app/core/api/data-aggregator.ts b/ui-ngx/src/app/core/api/data-aggregator.ts index 300998548c..9bc621fe22 100644 --- a/ui-ngx/src/app/core/api/data-aggregator.ts +++ b/ui-ngx/src/app/core/api/data-aggregator.ts @@ -25,7 +25,7 @@ import { SubscriptionTimewindow } from '@shared/models/time/time.models'; import { UtilsService } from '@core/services/utils.service'; -import { deepClone, isNumeric } from '@core/utils'; +import { deepClone, isNumber, isNumeric } from '@core/utils'; import Timeout = NodeJS.Timeout; export declare type onAggregatedData = (data: SubscriptionData, detectChanges: boolean) => void; @@ -92,20 +92,36 @@ declare type AggFunction = (aggData: AggData, value?: any) => void; const avg: AggFunction = (aggData: AggData, value?: any) => { aggData.count++; - aggData.sum += value; - aggData.aggValue = aggData.sum / aggData.count; + if (isNumber(value)) { + aggData.sum += value; + aggData.aggValue = aggData.sum / aggData.count; + } else { + aggData.aggValue = value; + } }; const min: AggFunction = (aggData: AggData, value?: any) => { - aggData.aggValue = Math.min(aggData.aggValue, value); + if (isNumber(value)) { + aggData.aggValue = Math.min(aggData.aggValue, value); + } else { + aggData.aggValue = value; + } }; const max: AggFunction = (aggData: AggData, value?: any) => { - aggData.aggValue = Math.max(aggData.aggValue, value); + if (isNumber(value)) { + aggData.aggValue = Math.max(aggData.aggValue, value); + } else { + aggData.aggValue = value; + } }; const sum: AggFunction = (aggData: AggData, value?: any) => { - aggData.aggValue = aggData.aggValue + value; + if (isNumber(value)) { + aggData.aggValue = aggData.aggValue + value; + } else { + aggData.aggValue = value; + } }; const count: AggFunction = (aggData: AggData) => { @@ -409,7 +425,7 @@ export class DataAggregator { } private convertValue(val: string): any { - if (!this.noAggregation || val && isNumeric(val) && Number(val).toString() === val) { + if (val && isNumeric(val) && (!this.noAggregation || this.noAggregation && Number(val).toString() === val)) { return Number(val); } return val; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts index a0950eb53f..6d10e154b0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts @@ -16,7 +16,7 @@ import { FormattedData, MapProviders, ReplaceInfo } from '@home/components/widget/lib/maps/map-models'; import { - createLabelFromDatasource, deepClone, + createLabelFromDatasource, hashCode, isDefined, isDefinedAndNotNull, @@ -127,7 +127,6 @@ export function aspectCache(imageUrl: string): Observable { export type TranslateFunc = (key: string, defaultTranslation?: string) => string; -const varsRegex = /\${([^}]*)}/g; const linkActionRegex = /([^<]*)<\/link-act>/g; const buttonActionRegex = /([^<]*)<\/button-act>/g; @@ -304,7 +303,8 @@ export const parseWithTranslation = { if (this.translateFn) { return this.translateFn(key, defaultTranslation); } else { - throw console.error('Translate not assigned'); + console.error('Translate not assigned'); + throw Error('Translate not assigned'); } }, parseTemplate(template: string, data: object, forceTranslate = false): string { @@ -334,7 +334,7 @@ export function parseData(input: DatasourceData[], dataIndex?: number): Formatte if (!obj.hasOwnProperty(el.dataKey.label) || el.data[dataIndex][1] !== '') { obj[el.dataKey.label] = el.data[dataIndex][1]; obj[el.dataKey.label + '|ts'] = el.data[dataIndex][0]; - if (el.dataKey.label === 'type') { + if (el.dataKey.label.toLowerCase() === 'type') { obj.deviceType = el.data[dataIndex][1]; } } @@ -360,28 +360,35 @@ export function flatData(input: FormattedData[]): FormattedData { } export function parseArray(input: DatasourceData[]): FormattedData[][] { - return _(input).groupBy(el => el?.datasource?.entityName) - .values().value().map((entityArray) => - entityArray[0].data.map((el, i) => { - const obj: FormattedData = { - entityName: entityArray[0]?.datasource?.entityName, - entityId: entityArray[0]?.datasource?.entityId, - entityType: entityArray[0]?.datasource?.entityType, - $datasource: entityArray[0]?.datasource, - dsIndex: i, - time: el[0], - deviceType: null - }; - entityArray.filter(e => e.data.length && e.data[i]).forEach(entity => { - obj[entity?.dataKey?.label] = entity?.data[i][1]; - obj[entity?.dataKey?.label + '|ts'] = entity?.data[0][0]; - if (entity?.dataKey?.label === 'type') { - obj.deviceType = entity?.data[0][1]; + return _(input).groupBy(el => el.datasource.entityName) + .values().value().map((entityArray, dsIndex) => { + const timeDataMap: {[time: number]: FormattedData} = {}; + entityArray.filter(e => e.data.length).forEach(entity => { + entity.data.forEach(tsData => { + const time = tsData[0]; + const value = tsData[1]; + let data = timeDataMap[time]; + if (!data) { + data = { + entityName: entity.datasource.entityName, + entityId: entity.datasource.entityId, + entityType: entity.datasource.entityType, + $datasource: entity.datasource, + dsIndex, + time, + deviceType: null + }; + timeDataMap[time] = data; + } + data[entity.dataKey.label] = value; + data[entity.dataKey.label + '|ts'] = time; + if (entity.dataKey.label.toLowerCase() === 'type') { + data.deviceType = value; } }); - return obj; - }) - ); + }); + return _.values(timeDataMap); + }); } export function parseFunction(source: any, params: string[] = ['def']): (...args: any[]) => any { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index fb79b44e35..5120fc8c9e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -474,9 +474,10 @@ export default abstract class LeafletMap { this.showPolygon = showPolygon; if (this.map) { const data = this.ctx.data; - const formattedData = parseData(this.ctx.data); + const formattedData = parseData(data); if (drawRoutes) { - this.updatePolylines(parseArray(data), false); + const polyData = parseArray(data); + this.updatePolylines(polyData, formattedData, false); } if (showPolygon) { this.updatePolygons(formattedData, false); @@ -633,7 +634,8 @@ export default abstract class LeafletMap { return polygon; } - updatePoints(pointsData: FormattedData[][], getTooltip: (point: FormattedData) => string) { + updatePoints(pointsData: FormattedData[][], + getTooltip: (point: FormattedData, points: FormattedData[]) => string) { if (pointsData.length) { if (this.points) { this.map.removeLayer(this.points); @@ -642,21 +644,25 @@ export default abstract class LeafletMap { } let pointColor = this.options.pointColor; for (const pointsList of pointsData) { - pointsList.filter(pdata => !!this.convertPosition(pdata)).forEach(data => { - if (this.options.useColorPointFunction) { - pointColor = safeExecute(this.options.colorPointFunction, [data, pointsData, data.dsIndex]); - } - const point = L.circleMarker(this.convertPosition(data), { - color: pointColor, - radius: this.options.pointSize - }); - if (!this.options.pointTooltipOnRightPanel) { - point.on('click', () => getTooltip(data)); - } else { - createTooltip(point, this.options, data.$datasource, getTooltip(data)); + for (let tsIndex = 0; tsIndex < pointsList.length; tsIndex++) { + const pdata = pointsList[tsIndex]; + if (!!this.convertPosition(pdata)) { + const dsData = pointsData.map(ds => ds[tsIndex]); + if (this.options.useColorPointFunction) { + pointColor = safeExecute(this.options.colorPointFunction, [pdata, dsData, pdata.dsIndex]); + } + const point = L.circleMarker(this.convertPosition(pdata), { + color: pointColor, + radius: this.options.pointSize + }); + if (!this.options.pointTooltipOnRightPanel) { + point.on('click', () => getTooltip(pdata, dsData)); + } else { + createTooltip(point, this.options, pdata.$datasource, getTooltip(pdata, dsData)); + } + this.points.addLayer(point); } - this.points.addLayer(point); - }); + } } if (pointsData.length) { this.map.addLayer(this.points); @@ -665,15 +671,15 @@ export default abstract class LeafletMap { // Polyline - updatePolylines(polyData: FormattedData[][], updateBounds = true, activePolyline?: FormattedData) { + updatePolylines(polyData: FormattedData[][], dsData: FormattedData[], updateBounds = true) { const keys: string[] = []; - polyData.forEach((dataSource: FormattedData[]) => { - const data = activePolyline || dataSource[0]; - if (dataSource.length && data.entityName === dataSource[0].entityName) { + polyData.forEach((tsData: FormattedData[], index) => { + const data = dsData[index]; + if (tsData.length && data.entityName === tsData[0].entityName) { if (this.polylines.get(data.entityName)) { - this.updatePolyline(data, dataSource, this.options, updateBounds); + this.updatePolyline(data, tsData, dsData, this.options, updateBounds); } else { - this.createPolyline(data, dataSource, this.options, updateBounds); + this.createPolyline(data, tsData, dsData, this.options, updateBounds); } keys.push(data.entityName); } @@ -689,9 +695,9 @@ export default abstract class LeafletMap { }); } - createPolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings, updateBounds = true) { + createPolyline(data: FormattedData, tsData: FormattedData[], dsData: FormattedData[], settings: PolylineSettings, updateBounds = true) { const poly = new Polyline(this.map, - dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings); + tsData.map(el => this.convertPosition(el)).filter(el => !!el), data, dsData, settings); if (updateBounds) { const bounds = poly.leafletPoly.getBounds(); this.fitBounds(bounds); @@ -699,10 +705,10 @@ export default abstract class LeafletMap { this.polylines.set(data.entityName, poly); } - updatePolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings, updateBounds = true) { + updatePolyline(data: FormattedData, tsData: FormattedData[], dsData: FormattedData[], settings: PolylineSettings, updateBounds = true) { const poly = this.polylines.get(data.entityName); const oldBounds = poly.leafletPoly.getBounds(); - poly.updatePolyline(dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings); + poly.updatePolyline(tsData.map(el => this.convertPosition(el)).filter(el => !!el), data, dsData, settings); const newBounds = poly.leafletPoly.getBounds(); if (updateBounds && oldBounds.toBBoxString() !== newBounds.toBBoxString()) { this.fitBounds(newBounds); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index d7110f0a4b..4c7e6e61fa 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -866,7 +866,7 @@ export const pathSchema = 'useColorFunction', { key: 'colorFunction', - helpId: 'widget/lib/map/trip_path_color_fn', + helpId: 'widget/lib/map/path_color_fn', type: 'javascript', condition: 'model.useColorFunction === true' }, @@ -961,7 +961,7 @@ export const pointSchema = 'useColorPointFunction', { key: 'colorPointFunction', - helpId: 'widget/lib/map/trip_path_point_color_fn', + helpId: 'widget/lib/map/path_point_color_fn', type: 'javascript', condition: 'model.useColorPointFunction === true' }, @@ -1150,7 +1150,7 @@ export const tripAnimationSchema = { { key: 'labelFunction', type: 'javascript', - helpId: 'widget/lib/map/trip_label_fn', + helpId: 'widget/lib/map/label_fn', condition: 'model.showLabel === true && model.useLabelFunction === true' }, 'showTooltip', @@ -1184,7 +1184,7 @@ export const tripAnimationSchema = { { key: 'tooltipFunction', type: 'javascript', - helpId: 'widget/lib/map/trip_tooltip_fn', + helpId: 'widget/lib/map/tooltip_fn', condition: 'model.showTooltip === true && model.useTooltipFunction === true' }, 'rotationAngle', @@ -1201,7 +1201,7 @@ export const tripAnimationSchema = { { key: 'markerImageFunction', type: 'javascript', - helpId: 'widget/lib/map/trip_marker_image_fn', + helpId: 'widget/lib/map/marker_image_fn', condition: 'model.useMarkerImageFunction === true' }, { diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html index b98a00263b..cd539a4a50 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html @@ -16,9 +16,7 @@ -->
    -
    - {{label}} -
    +
    diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index 2581da88ad..e614c80455 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -30,7 +30,7 @@ import { import { FormattedData, MapProviders, TripAnimationSettings } from '@home/components/widget/lib/maps/map-models'; import { addCondition, addGroupInfo, addToSchema, initSchema } from '@app/core/schema-utils'; import { mapPolygonSchema, pathSchema, pointSchema, tripAnimationSchema } from '@home/components/widget/lib/maps/schemes'; -import { DomSanitizer } from '@angular/platform-browser'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { findAngle, getProviderSchema, @@ -70,13 +70,14 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy mapWidget: MapWidgetInterface; historicalData: FormattedData[][]; normalizationStep: number; - interpolatedTimeData = []; + interpolatedTimeData: {[time: number]: FormattedData}[] = []; + formattedInterpolatedTimeData: FormattedData[][] = []; widgetConfig: WidgetConfig; settings: TripAnimationSettings; mainTooltips = []; visibleTooltip = false; activeTrip: FormattedData; - label: string; + label: SafeHtml; minTime: number; maxTime: number; anchors: number[] = []; @@ -117,6 +118,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy const subscription = this.ctx.defaultSubscription; subscription.callbacks.onDataUpdated = () => { this.historicalData = parseArray(this.ctx.data).filter(arr => arr.length); + this.interpolatedTimeData.length = 0; + this.formattedInterpolatedTimeData.length = 0; if (this.historicalData.length) { this.calculateIntervals(); this.timeUpdated(this.minTime); @@ -146,6 +149,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy timeUpdated(time: number) { this.currentTime = time; + // get point for each datasource associated with time const currentPosition = this.interpolatedTimeData .map(dataSource => dataSource[time]); for (let j = 0; j < this.interpolatedTimeData.length; j++) { @@ -171,20 +175,20 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy currentPosition[j] = this.calculateLastPoints(this.interpolatedTimeData[j], time); } } - this.calcLabel(); + this.calcLabel(currentPosition); this.calcMainTooltip(currentPosition); if (this.mapWidget && this.mapWidget.map && this.mapWidget.map.map) { - const formattedInterpolatedTimeData = this.interpolatedTimeData.map(ds => _.values(ds)); - this.mapWidget.map.updatePolylines(formattedInterpolatedTimeData, true); + this.mapWidget.map.updatePolylines(this.formattedInterpolatedTimeData, currentPosition, true); if (this.settings.showPolygon) { - this.mapWidget.map.updatePolygons(this.interpolatedTimeData); + this.mapWidget.map.updatePolygons(currentPosition); } if (this.settings.showPoints) { - this.mapWidget.map.updatePoints(formattedInterpolatedTimeData.map(ds => _.union(ds)), this.calcTooltip); + this.mapWidget.map.updatePoints(this.formattedInterpolatedTimeData, this.calcTooltip); } this.mapWidget.map.updateMarkers(currentPosition, true, (trip) => { this.activeTrip = trip; this.timeUpdated(this.currentTime); + this.cd.markForCheck(); }); } } @@ -215,41 +219,44 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.maxTime = dataSource[dataSource.length - 1]?.time || -Infinity; this.interpolatedTimeData[index] = this.interpolateArray(dataSource); }); + this.formattedInterpolatedTimeData = this.interpolatedTimeData.map(ds => _.values(ds)); if (!this.activeTrip) { this.activeTrip = this.interpolatedTimeData.map(dataSource => dataSource[this.minTime]).filter(ds => ds)[0]; } if (this.useAnchors) { const anchorDate = Object.entries(_.union(this.interpolatedTimeData)[0]); this.anchors = anchorDate - .filter((data: [string, FormattedData]) => safeExecute(this.settings.pointAsAnchorFunction, [data[1], anchorDate, data[1].dsIndex])) + .filter((data: [string, FormattedData], tsIndex) => safeExecute(this.settings.pointAsAnchorFunction, [data[1], + this.formattedInterpolatedTimeData.map(ds => ds[tsIndex]), data[1].dsIndex])) .map(data => parseInt(data[0], 10)); } } - calcTooltip = (point: FormattedData): string => { + calcTooltip = (point: FormattedData, points: FormattedData[]): string => { const data = point ? point : this.activeTrip; const tooltipPattern: string = this.settings.useTooltipFunction ? - safeExecute(this.settings.tooltipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern; + safeExecute(this.settings.tooltipFunction, + [data, points, point.dsIndex]) : this.settings.tooltipPattern; return parseWithTranslation.parseTemplate(tooltipPattern, data, true); } private calcMainTooltip(points: FormattedData[]): void { const tooltips = []; for (const point of points) { - tooltips.push(this.sanitizer.sanitize(SecurityContext.HTML, this.calcTooltip(point))); + tooltips.push(this.sanitizer.sanitize(SecurityContext.HTML, this.calcTooltip(point, points))); } this.mainTooltips = tooltips; } - calcLabel() { - const data = this.activeTrip; + calcLabel(points: FormattedData[]) { + const data = points[this.activeTrip.dsIndex]; const labelText: string = this.settings.useLabelFunction ? - safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; - this.label = (parseWithTranslation.parseTemplate(labelText, data, true)); + safeExecute(this.settings.labelFunction, [data, points, data.dsIndex]) : this.settings.label; + this.label = this.sanitizer.bypassSecurityTrustHtml(parseWithTranslation.parseTemplate(labelText, data, true)); } - interpolateArray(originData: FormattedData[]) { - const result = {}; + interpolateArray(originData: FormattedData[]): {[time: number]: FormattedData} { + const result: {[time: number]: FormattedData} = {}; const latKeyName = this.settings.latKeyName; const lngKeyName = this.settings.lngKeyName; for (const data of originData) { diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/map_fn_args.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/map_fn_args.md index d1275ee871..7a4f24f0ac 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/map_fn_args.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/map_fn_args.md @@ -1,10 +1,10 @@ -
  • data: FormattedData - A FormattedData object associated with marker.
    +
  • data: FormattedData - A FormattedData object associated with marker or data point of the route.
    Represents basic entity properties (ex. entityId, entityName)
    and provides access to other entity attributes/timeseries declared in widget datasource configuration.
  • -
  • dsData: FormattedData[] - All available widget data (entities) as array of FormattedData objects
    +
  • dsData: FormattedData[] - All available data associated with markers or routes data points as array of FormattedData objects
    resolved from configured datasources. Each object represents basic entity properties (ex. entityId, entityName)
    and provides access to other entity attributes/timeseries declared in widget datasource configuration.
  • -
  • dsIndex number - index of the current marker data in dsData array.
    +
  • dsIndex number - index of the current marker data or route data point in dsData array.
    Note: The data argument is equivalent to dsData[dsIndex] expression.
  • diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md similarity index 94% rename from ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_color_fn.md rename to ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md index 5afcd678c7..056e47d0eb 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md @@ -10,7 +10,7 @@ A JavaScript function used to compute color of the trip path. **Parameters:**
      - {% include widget/lib/map/trip_fn_args %} + {% include widget/lib/map/map_fn_args %}
    **Returns:** diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_point_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md similarity index 95% rename from ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_point_color_fn.md rename to ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md index 3b16a3ef22..30f5e0f4d5 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_path_point_color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md @@ -10,7 +10,7 @@ A JavaScript function used to compute color of the trip path point. **Parameters:**
      - {% include widget/lib/map/trip_fn_args %} + {% include widget/lib/map/map_fn_args %}
    **Returns:** diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/tooltip_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/tooltip_fn.md index 6468b8a973..d4d97d99b6 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/tooltip_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/tooltip_fn.md @@ -5,7 +5,7 @@ *function (data, dsData, dsIndex): string* -A JavaScript function used to compute text or HTML code to be displayed in the marker tooltip. +A JavaScript function used to compute text or HTML code to be displayed in the marker, point or polygon tooltip. **Parameters:** @@ -15,7 +15,7 @@ A JavaScript function used to compute text or HTML code to be displayed in the m **Returns:** -Should return string value presenting text or HTML for the marker tooltip. +Should return string value presenting text or HTML for the tooltip.
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_fn_args.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_fn_args.md deleted file mode 100644 index a6adebddb6..0000000000 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_fn_args.md +++ /dev/null @@ -1,11 +0,0 @@ -
  • data: FormattedData - A FormattedData object associated with the point of the trip.
    - Represents basic entity properties (ex. entityId, entityName)
    and provides access to other entity attributes/timeseries declared in widget datasource configuration. -
  • -
  • dsData: FormattedData[][] - two-dimensional array of FormattedData objects presenting
    - array of trips (entities with timeseries data) resolved from configured datasources.
    - Each element of array is particular entity trip data presented as array of FormattedData object (trip point).
    - Each object represents basic entity properties (ex. entityId, entityName)
    - and provides access to other entity attributes/timeseries declared in widget datasource configuration. -
  • -
  • dsIndex number - index of the current trip data in dsData array. -
  • diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_label_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_label_fn.md deleted file mode 100644 index 0203a592f8..0000000000 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_label_fn.md +++ /dev/null @@ -1,40 +0,0 @@ -#### Trip animation widget label function - -
    -
    - -*function (data, dsData, dsIndex): string* - -A JavaScript function used to compute text or HTML code of the marker label. - -**Parameters:** - -
      - {% include widget/lib/map/trip_fn_args %} -
    - -**Returns:** - -Should return string value presenting text or HTML of the marker label. - -
    - -##### Examples - -* Display styled label with corresponding latest telemetry data for `energy meter` or `thermometer` device types: - -```javascript -var deviceType = data['Type']; -if (typeof deviceType !== undefined) { - if (deviceType == "energy meter") { - return '${entityName}, ${energy:2} kWt'; - } else if (deviceType == "thermometer") { - return '${entityName}, ${temperature:2} °C'; - } -} -return data.entityName; -{:copy-code} -``` - -
    -
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_marker_image_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_marker_image_fn.md deleted file mode 100644 index b5389985eb..0000000000 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_marker_image_fn.md +++ /dev/null @@ -1,62 +0,0 @@ -#### Marker image function - -
    -
    - -*function (data, images, dsData, dsIndex): {url: string, size: number}* - -A JavaScript function used to compute marker image. - -**Parameters:** - -
      - {% include widget/lib/map/trip_fn_args %} -
    - -**Returns:** - -Should return marker image data having the following structure: - -```typescript -{ - url: string, - size: number -} -``` - -- *url* - marker image url; -- *size* - marker image size; - -In case no data is returned, default marker image will be used. - -
    - -##### Examples - -
      -
    • -Calculate image url depending on temperature telemetry value for thermometer device type.
      -Let's assume 4 images are defined in Marker images section. Each image corresponds to particular temperature level: -
    • -
    - -```javascript -var type = data['Type']; -if (type == 'thermometer') { - var res = { - url: images[0], - size: 40 - } - var temperature = data['temperature']; - if (typeof temperature !== undefined) { - var percent = (temperature + 60)/120; - var index = Math.min(3, Math.floor(4 * percent)); - res.url = images[index]; - } - return res; -} -{:copy-code} -``` - -
    -
    diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_point_as_anchor_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_point_as_anchor_fn.md index 788e2bb189..e938532b78 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_point_as_anchor_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_point_as_anchor_fn.md @@ -10,7 +10,7 @@ A JavaScript function evaluating whether to use trip point as time anchor used i **Parameters:**
      - {% include widget/lib/map/trip_fn_args %} + {% include widget/lib/map/map_fn_args %}
    **Returns:** diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_tooltip_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_tooltip_fn.md deleted file mode 100644 index 6678dc9b2e..0000000000 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/trip_tooltip_fn.md +++ /dev/null @@ -1,40 +0,0 @@ -#### Trip animation widget tooltip function - -
    -
    - -*function (data, dsData, dsIndex): string* - -A JavaScript function used to compute text or HTML code to be displayed in the marker tooltip. - -**Parameters:** - -
      - {% include widget/lib/map/trip_fn_args %} -
    - -**Returns:** - -Should return string value presenting text or HTML for the marker tooltip. - -
    - -##### Examples - -* Display details with corresponding telemetry data for `thermostat` device type: - -```javascript -var deviceType = data['Type']; -if (typeof deviceType !== undefined) { - if (deviceType == "energy meter") { - return '${entityName}
    Energy: ${energy:2} kWt
    '; - } else if (deviceType == "thermometer") { - return '${entityName}
    Temperature: ${temperature:2} °C
    '; - } -} -return data.entityName; -{:copy-code} -``` - -
    -
    From 0ec125a766059868a1bcd15d684f3e98fbe719cc Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 21 Oct 2021 15:52:40 +0300 Subject: [PATCH 110/303] Update rule nodes UI --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fe4b5482bf..17f2ee6af1 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 @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
    "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
    tb.rulenode.notify-device-hint
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
    \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
    \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
    \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
    \n \n \n \n
    \n \n
    \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
    \n
    \n
    \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
    \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
    tb.rulenode.create-entity-if-not-exists-hint
    \n
    \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
    tb.rulenode.remove-current-relations-hint
    \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
    tb.rulenode.change-originator-to-related-entity-hint
    \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
    \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
    tb.rulenode.use-metadata-period-in-seconds-patterns-hint
    \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
    \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
    tb.rulenode.delete-relation-hint
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
    \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
    \n \n \n \n
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
    \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
    \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
    \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
    \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
    \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
    \n
    \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
    \n
    \n
    \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
    \n
    \n \n
    \n \n
    \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
    \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
    \n
    relation.relation-type
    \n \n \n
    device.device-types
    \n \n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
    \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
    \n
    relation.relation-filters
    \n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-message-types-found\n
    \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
    \n
    \n
    \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
    \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
    \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
    {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
    \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
    \n
    \n
    \n
    \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
    \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
    \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
    \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
    \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
    \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
    tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
    \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
    \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
    \n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
    \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
    \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
    \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
    \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
    \n
    \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
    \n
    \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
    \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
    \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
    \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
    \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
    \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
    \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
    \n
    \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
    \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
    \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
    \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
    \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
    \n
    \n
    \n
    \n
    \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
    \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
    \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
    \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
    tb.rulenode.separator-hint
    \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
    tb.rulenode.separator-hint
    \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
    tb.rulenode.check-all-keys-hint
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
    \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
    tb.rulenode.check-relation-hint
    \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
    \n \n \n \n \n
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
    \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
    \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n
    \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
    \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
    \n \n \n \n
    \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
    \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-alarm-status-matching\n
    \n
    \n
    \n
    \n
    \n \n
    \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
    \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
    \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-entity-details-matching\n
    \n
    \n
    \n
    \n
    \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
    tb.rulenode.add-to-metadata-hint
    \n
    \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
    \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
    tb.rulenode.tell-failure-if-absent-hint
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
    \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
    tb.rulenode.tell-failure-if-absent-hint
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
    \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
    \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
    \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
    tb.rulenode.use-metadata-interval-patterns-hint
    \n
    \n
    \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
    \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
    \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
    \n
    \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
    \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
    \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
    \n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
    \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
    "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
    tb.rulenode.notify-device-hint
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
    \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
    \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
    \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
    \n \n \n \n
    \n \n
    \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
    \n
    \n
    \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
    \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
    \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
    tb.rulenode.create-entity-if-not-exists-hint
    \n
    \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
    tb.rulenode.remove-current-relations-hint
    \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
    tb.rulenode.change-originator-to-related-entity-hint
    \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
    \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
    tb.rulenode.use-metadata-period-in-seconds-patterns-hint
    \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
    \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
    tb.rulenode.delete-relation-hint
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
    \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
    \n \n \n \n
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
    \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
    \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
    \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
    \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
    \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
    \n
    \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
    \n
    \n
    \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
    \n
    \n \n
    \n \n
    \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
    \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
    \n
    relation.relation-type
    \n \n \n
    device.device-types
    \n \n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
    \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
    \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
    \n
    relation.relation-filters
    \n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-message-types-found\n
    \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
    \n
    \n
    \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
    \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
    \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
    {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
    \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
    \n
    \n
    \n
    \n
    \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
    \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
    \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
    \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
    \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
    \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
    \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
    tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
    \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
    \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
    \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
    \n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
    \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
    \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
    \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
    \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
    \n
    \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
    \n
    \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
    \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
    \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
    \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
    \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
    \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
    \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
    \n
    \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
    \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
    \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
    \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
    \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
    \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
    \n
    \n
    \n
    \n
    \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
    \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
    \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
    \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
    \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
    tb.rulenode.separator-hint
    \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
    tb.rulenode.separator-hint
    \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
    tb.rulenode.check-all-keys-hint
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
    \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
    tb.rulenode.check-relation-hint
    \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
    \n \n \n \n \n
    \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
    \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
    \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
    \n
    \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
    \n
    \n
    \n
    \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
    \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
    \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
    \n \n \n \n
    \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
    \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-alarm-status-matching\n
    \n
    \n
    \n
    \n
    \n \n
    \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
    \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
    \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
    \n
    \n tb.rulenode.no-entity-details-matching\n
    \n
    \n
    \n
    \n
    \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
    tb.rulenode.add-to-metadata-hint
    \n
    \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
    \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
    tb.rulenode.tell-failure-if-absent-hint
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
    \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
    tb.rulenode.tell-failure-if-absent-hint
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
    \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
    \n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.aggregationTypes=a.AggregationType,n.aggregations=Object.keys(a.AggregationType),n.aggregationTypesTranslations=a.aggregationTranslations,n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[i.Validators.required]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
    \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
    \n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
    \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
    tb.rulenode.use-metadata-interval-patterns-hint
    \n
    \n
    \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
    \n
    \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
    \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
    \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
    \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
    \n
    \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
    \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
    \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
    \n \n \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
    \n \n \n \n
    \n \n
    \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
    \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
    \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 3382333634102b3daf917be1181d207d50eee0ec Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 21 Oct 2021 17:05:05 +0300 Subject: [PATCH 111/303] Restore after violation of the OOP rules --- .../server/controller/EventController.java | 4 +- .../common/data/event/BaseEventFilter.java | 57 ------------------- .../server/common/data/event/DebugEvent.java | 26 ++++++++- .../common/data/event/ErrorEventFilter.java | 12 +++- .../data/event/LifeCycleEventFilter.java | 14 ++++- .../data/event/StatisticsEventFilter.java | 12 +++- 6 files changed, 62 insertions(+), 63 deletions(-) delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/event/BaseEventFilter.java diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 097e18d406..32911a6d14 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -28,7 +28,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Event; -import org.thingsboard.server.common.data.event.BaseEventFilter; +import org.thingsboard.server.common.data.event.EventFilter; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -162,7 +162,7 @@ public class EventController extends BaseController { @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @ApiParam(value = "A JSON value representing the event filter.", required = true) - @RequestBody BaseEventFilter eventFilter, + @RequestBody EventFilter eventFilter, @ApiParam(value = EVENT_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EVENT_SORT_PROPERTY_ALLOWABLE_VALUES) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/BaseEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/BaseEventFilter.java deleted file mode 100644 index cd3335b17f..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/BaseEventFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.common.data.event; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; - -@ApiModel -@Data -public abstract class BaseEventFilter implements EventFilter { - - @ApiModelProperty(position = 1, value = "String value representing msg direction type (incoming to entity or outcoming from entity)", allowableValues = "IN, OUT") - protected String msgDirectionType; - @ApiModelProperty(position = 2, value = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152") - protected String server; - @ApiModelProperty(position = 3, value = "The case insensitive 'contains' filter based on data (key and value) for the message.", example = "humidity") - protected String dataSearch; - @ApiModelProperty(position = 4, value = "The case insensitive 'contains' filter based on metadata (key and value) for the message.", example = "deviceName") - protected String metadataSearch; - @ApiModelProperty(position = 5, value = "String value representing the entity type", allowableValues = "DEVICE") - protected String entityName; - @ApiModelProperty(position = 6, value = "String value representing the type of message routing", example = "Success") - protected String relationType; - @ApiModelProperty(position = 7, value = "String value representing the entity id in the event body (originator of the message)", example = "de9d54a0-2b7a-11ec-a3cc-23386423d98f") - protected String entityId; - @ApiModelProperty(position = 8, value = "String value representing the message type", example = "POST_TELEMETRY_REQUEST") - protected String msgType; - @ApiModelProperty(position = 9, value = "Boolean value to filter the errors", allowableValues = "false, true") - protected boolean isError; - @ApiModelProperty(position = 10, value = "The case insensitive 'contains' filter based on error message", example = "not present in the DB") - protected String errorStr; - @ApiModelProperty(position = 11, value = "String value representing the method name when the error happened", example = "onClusterEventMsg") - protected String method; - @ApiModelProperty(position = 12, value = "The minimum number of successfully processed messages", example = "25") - protected Integer messagesProcessed; - @ApiModelProperty(position = 13, value = "The minimum number of errors occurred during messages processing", example = "30") - protected Integer errorsOccurred; - @ApiModelProperty(position = 14, value = "String value representing the lifecycle event type", example = "STARTED") - protected String event; - @ApiModelProperty(position = 15, value = "String value representing status of the lifecycle event", allowableValues = "Success, Failure") - protected String status; - -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java index f318b40c0b..939e85d68c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java @@ -16,10 +16,34 @@ package org.thingsboard.server.common.data.event; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; import org.thingsboard.server.common.data.StringUtils; +@Data @ApiModel -public abstract class DebugEvent extends BaseEventFilter implements EventFilter { +public abstract class DebugEvent implements EventFilter { + + @ApiModelProperty(position = 1, value = "String value representing msg direction type (incoming to entity or outcoming from entity)", allowableValues = "IN, OUT") + protected String msgDirectionType; + @ApiModelProperty(position = 2, value = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152") + protected String server; + @ApiModelProperty(position = 3, value = "The case insensitive 'contains' filter based on data (key and value) for the message.", example = "humidity") + protected String dataSearch; + @ApiModelProperty(position = 4, value = "The case insensitive 'contains' filter based on metadata (key and value) for the message.", example = "deviceName") + protected String metadataSearch; + @ApiModelProperty(position = 5, value = "String value representing the entity type", allowableValues = "DEVICE") + protected String entityName; + @ApiModelProperty(position = 6, value = "String value representing the type of message routing", example = "Success") + protected String relationType; + @ApiModelProperty(position = 7, value = "String value representing the entity id in the event body (originator of the message)", example = "de9d54a0-2b7a-11ec-a3cc-23386423d98f") + protected String entityId; + @ApiModelProperty(position = 8, value = "String value representing the message type", example = "POST_TELEMETRY_REQUEST") + protected String msgType; + @ApiModelProperty(position = 9, value = "Boolean value to filter the errors", allowableValues = "false, true") + protected boolean isError; + @ApiModelProperty(position = 10, value = "The case insensitive 'contains' filter based on error message", example = "not present in the DB") + protected String errorStr; public void setIsError(boolean isError) { this.isError = isError; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java index 6a41f110b4..aa86c0b9a2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java @@ -16,10 +16,20 @@ package org.thingsboard.server.common.data.event; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; import org.thingsboard.server.common.data.StringUtils; +@Data @ApiModel -public class ErrorEventFilter extends BaseEventFilter implements EventFilter { +public class ErrorEventFilter implements EventFilter { + + @ApiModelProperty(position = 1, value = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152") + protected String server; + @ApiModelProperty(position = 2, value = "String value representing the method name when the error happened", example = "onClusterEventMsg") + protected String method; + @ApiModelProperty(position = 3, value = "The case insensitive 'contains' filter based on error message", example = "not present in the DB") + protected String errorStr; @Override public EventType getEventType() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java index dcdce9422a..f87ace2731 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java @@ -16,10 +16,22 @@ package org.thingsboard.server.common.data.event; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; import org.thingsboard.server.common.data.StringUtils; +@Data @ApiModel -public class LifeCycleEventFilter extends BaseEventFilter implements EventFilter { +public class LifeCycleEventFilter implements EventFilter { + + @ApiModelProperty(position = 1, value = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152") + protected String server; + @ApiModelProperty(position = 2, value = "String value representing the lifecycle event type", example = "STARTED") + protected String event; + @ApiModelProperty(position = 3, value = "String value representing status of the lifecycle event", allowableValues = "Success, Failure") + protected String status; + @ApiModelProperty(position = 4, value = "The case insensitive 'contains' filter based on error message", example = "not present in the DB") + protected String errorStr; @Override public EventType getEventType() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java index 3e2635da97..4c16e0bde5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java @@ -16,10 +16,20 @@ package org.thingsboard.server.common.data.event; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; import org.thingsboard.server.common.data.StringUtils; +@Data @ApiModel -public class StatisticsEventFilter extends BaseEventFilter implements EventFilter { +public class StatisticsEventFilter implements EventFilter { + + @ApiModelProperty(position = 1, value = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152") + protected String server; + @ApiModelProperty(position = 2, value = "The minimum number of successfully processed messages", example = "25") + protected Integer messagesProcessed; + @ApiModelProperty(position = 3, value = "The minimum number of errors occurred during messages processing", example = "30") + protected Integer errorsOccurred; @Override public EventType getEventType() { From 7ba4fbf165a5416088ad85ca84d85ff4a1d9a280 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 21 Oct 2021 17:20:49 +0300 Subject: [PATCH 112/303] UI: Fixed map-utils parse data - not correct index (timeseries without aggregation) --- .../components/widget/lib/maps/common-maps-utils.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts index 6d10e154b0..9f1810f82f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts @@ -330,12 +330,12 @@ export function parseData(input: DatasourceData[], dataIndex?: number): Formatte deviceType: null }; entityArray.filter(el => el.data.length).forEach(el => { - dataIndex = isDefined(dataIndex) ? dataIndex : el.data.length - 1; - if (!obj.hasOwnProperty(el.dataKey.label) || el.data[dataIndex][1] !== '') { - obj[el.dataKey.label] = el.data[dataIndex][1]; - obj[el.dataKey.label + '|ts'] = el.data[dataIndex][0]; + const index = isDefined(dataIndex) ? dataIndex : el.data.length - 1; + if (!obj.hasOwnProperty(el.dataKey.label) || el.data[index][1] !== '') { + obj[el.dataKey.label] = el.data[index][1]; + obj[el.dataKey.label + '|ts'] = el.data[index][0]; if (el.dataKey.label.toLowerCase() === 'type') { - obj.deviceType = el.data[dataIndex][1]; + obj.deviceType = el.data[index][1]; } } }); From e2676f30daf9ad78d127312c806a5f3478dc71d0 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 21 Oct 2021 18:27:48 +0300 Subject: [PATCH 113/303] Added access validation for RPC --- .../controller/AbstractRpcController.java | 2 +- .../server/controller/RpcV2Controller.java | 26 +++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java b/application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java index 98294b241a..bb71116d08 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java @@ -60,7 +60,7 @@ public abstract class AbstractRpcController extends BaseController { protected TbCoreDeviceRpcService deviceRpcService; @Autowired - private AccessValidator accessValidator; + protected AccessValidator accessValidator; @Value("${server.rest.server_side_rpc.min_timeout:5000}") protected long minTimeout; diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index fa2d4b5ae7..0a594336ad 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.controller; +import com.google.common.util.concurrent.FutureCallback; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; @@ -45,7 +46,9 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.rpc.RemoveRpcActorMsg; import org.thingsboard.server.service.security.permission.Operation; +import org.thingsboard.server.service.telemetry.exception.ToErrorResponseEntity; +import javax.annotation.Nullable; import java.util.UUID; import static org.thingsboard.server.common.data.DataConstants.RPC_DELETED; @@ -151,7 +154,7 @@ public class RpcV2Controller extends AbstractRpcController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET) @ResponseBody - public PageData getPersistedRpcByDevice( + public DeferredResult getPersistedRpcByDevice( @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(DEVICE_ID) String strDeviceId, @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @@ -171,7 +174,26 @@ public class RpcV2Controller extends AbstractRpcController { TenantId tenantId = getCurrentUser().getTenantId(); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); DeviceId deviceId = new DeviceId(UUID.fromString(strDeviceId)); - return checkNotNull(rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink)); + final DeferredResult response = new DeferredResult<>(); + accessValidator.validate(getCurrentUser(), Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<>() { + @Override + public void onSuccess(@Nullable DeferredResult result) { + PageData rpcCalls = rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink); + response.setResult(new ResponseEntity<>(rpcCalls, HttpStatus.OK)); + } + + @Override + public void onFailure(Throwable e) { + ResponseEntity entity; + if (e instanceof ToErrorResponseEntity) { + entity = ((ToErrorResponseEntity) e).toErrorResponseEntity(); + } else { + entity = new ResponseEntity(HttpStatus.UNAUTHORIZED); + } + response.setResult(entity); + } + })); + return response; } catch (Exception e) { throw handleException(e); } From a852e11a3da348c1e1400f3068821a74865a5ec6 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Thu, 21 Oct 2021 16:09:22 +0300 Subject: [PATCH 114/303] Refactor bulk import --- .../server/service/device/DeviceBulkImportService.java | 4 +++- .../server/service/importing/AbstractBulkImportService.java | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java index 707674f6ba..6e31fa1d73 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java @@ -113,8 +113,10 @@ public class DeviceBulkImportService extends AbstractBulkImportService { DeviceProfile deviceProfile; if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { deviceProfile = setUpLwM2mDeviceProfile(user.getTenantId(), device); - } else { + } else if (StringUtils.isNotEmpty(device.getType())) { deviceProfile = deviceProfileService.findOrCreateDeviceProfile(user.getTenantId(), device.getType()); + } else { + deviceProfile = deviceProfileService.findDefaultDeviceProfile(user.getTenantId()); } device.setDeviceProfileId(deviceProfile.getId()); diff --git a/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java index a1e3ff16ef..bbd18a1f73 100644 --- a/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java @@ -23,6 +23,8 @@ import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.cluster.TbClusterService; @@ -93,7 +95,11 @@ public abstract class AbstractBulkImportService result = new BulkImportResult<>(); CountDownLatch completionLatch = new CountDownLatch(entitiesData.size()); + SecurityContext securityContext = SecurityContextHolder.getContext(); + entitiesData.forEach(entityData -> DonAsynchron.submit(() -> { + SecurityContextHolder.setContext(securityContext); + ImportedEntityInfo importedEntityInfo = saveEntity(request, entityData.getFields(), user); E entity = importedEntityInfo.getEntity(); From 7f1f29877449ecedfd448c3d0f628acc1c39a8a9 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 15 Oct 2021 19:17:15 +0300 Subject: [PATCH 115/303] cassandra buffered rate executor: separate beans for read and write operations --- .../server/actors/ActorSystemContext.java | 10 +- .../actors/ruleChain/DefaultTbContext.java | 9 +- .../dao/nosql/CassandraAbstractDao.java | 24 +++-- ...=> CassandraBufferedRateReadExecutor.java} | 75 +++------------ .../CassandraBufferedRateWriteExecutor.java | 95 +++++++++++++++++++ .../util/AbstractBufferedRateExecutor.java | 76 +++++++++++++-- .../nosql/CassandraPartitionsCacheTest.java | 11 ++- .../rule/engine/api/TbContext.java | 4 +- .../TbSaveToCustomCassandraTableNode.java | 2 +- 9 files changed, 219 insertions(+), 87 deletions(-) rename dao/src/main/java/org/thingsboard/server/dao/nosql/{CassandraBufferedRateExecutor.java => CassandraBufferedRateReadExecutor.java} (50%) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateWriteExecutor.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index cf9537fb83..6eaddc768a 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -59,7 +59,8 @@ import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.event.EventService; -import org.thingsboard.server.dao.nosql.CassandraBufferedRateExecutor; +import org.thingsboard.server.dao.nosql.CassandraBufferedRateReadExecutor; +import org.thingsboard.server.dao.nosql.CassandraBufferedRateWriteExecutor; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.resource.ResourceService; @@ -85,7 +86,6 @@ import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; import org.thingsboard.server.service.rpc.TbRpcService; import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; -import org.thingsboard.server.service.script.JsExecutorService; import org.thingsboard.server.service.script.JsInvokeService; import org.thingsboard.server.service.session.DeviceSessionCacheService; import org.thingsboard.server.service.sms.SmsExecutorService; @@ -421,7 +421,11 @@ public class ActorSystemContext { @Autowired(required = false) @Getter - private CassandraBufferedRateExecutor cassandraBufferedRateExecutor; + private CassandraBufferedRateReadExecutor cassandraBufferedRateReadExecutor; + + @Autowired(required = false) + @Getter + private CassandraBufferedRateWriteExecutor cassandraBufferedRateWriteExecutor; @Autowired(required = false) @Getter diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 8971cf1a23..e3896b87a9 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -557,8 +557,13 @@ class DefaultTbContext implements TbContext { } @Override - public TbResultSetFuture submitCassandraTask(CassandraStatementTask task) { - return mainCtx.getCassandraBufferedRateExecutor().submit(task); + public TbResultSetFuture submitCassandraReadTask(CassandraStatementTask task) { + return mainCtx.getCassandraBufferedRateReadExecutor().submit(task); + } + + @Override + public TbResultSetFuture submitCassandraWriteTask(CassandraStatementTask task) { + return mainCtx.getCassandraBufferedRateWriteExecutor().submit(task); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java index c121073d55..4cfb4b6dc9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.cassandra.CassandraCluster; import org.thingsboard.server.dao.cassandra.guava.GuavaSession; +import org.thingsboard.server.dao.util.BufferedRateExecutor; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -40,7 +41,10 @@ public abstract class CassandraAbstractDao { private ConcurrentMap preparedStatementMap = new ConcurrentHashMap<>(); @Autowired - private CassandraBufferedRateExecutor rateLimiter; + private CassandraBufferedRateReadExecutor rateReadLimiter; + + @Autowired + private CassandraBufferedRateWriteExecutor rateWriteLimiter; private GuavaSession session; @@ -61,36 +65,38 @@ public abstract class CassandraAbstractDao { } protected AsyncResultSet executeRead(TenantId tenantId, Statement statement) { - return execute(tenantId, statement, defaultReadLevel); + return execute(tenantId, statement, defaultReadLevel, rateReadLimiter); } protected AsyncResultSet executeWrite(TenantId tenantId, Statement statement) { - return execute(tenantId, statement, defaultWriteLevel); + return execute(tenantId, statement, defaultWriteLevel, rateWriteLimiter); } protected TbResultSetFuture executeAsyncRead(TenantId tenantId, Statement statement) { - return executeAsync(tenantId, statement, defaultReadLevel); + return executeAsync(tenantId, statement, defaultReadLevel, rateReadLimiter); } protected TbResultSetFuture executeAsyncWrite(TenantId tenantId, Statement statement) { - return executeAsync(tenantId, statement, defaultWriteLevel); + return executeAsync(tenantId, statement, defaultWriteLevel, rateWriteLimiter); } - private AsyncResultSet execute(TenantId tenantId, Statement statement, ConsistencyLevel level) { + private AsyncResultSet execute(TenantId tenantId, Statement statement, ConsistencyLevel level, + BufferedRateExecutor rateExecutor) { if (log.isDebugEnabled()) { log.debug("Execute cassandra statement {}", statementToString(statement)); } - return executeAsync(tenantId, statement, level).getUninterruptibly(); + return executeAsync(tenantId, statement, level, rateExecutor).getUninterruptibly(); } - private TbResultSetFuture executeAsync(TenantId tenantId, Statement statement, ConsistencyLevel level) { + private TbResultSetFuture executeAsync(TenantId tenantId, Statement statement, ConsistencyLevel level, + BufferedRateExecutor rateExecutor) { if (log.isDebugEnabled()) { log.debug("Execute cassandra async statement {}", statementToString(statement)); } if (statement.getConsistencyLevel() == null) { statement.setConsistencyLevel(level); } - return rateLimiter.submit(new CassandraStatementTask(tenantId, getSession(), statement)); + return rateExecutor.submit(new CassandraStatementTask(tenantId, getSession(), statement)); } private static String statementToString(Statement statement) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateExecutor.java b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateReadExecutor.java similarity index 50% rename from dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateExecutor.java rename to dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateReadExecutor.java index ac61a73f0c..839ca16483 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateExecutor.java +++ b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateReadExecutor.java @@ -22,9 +22,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.stats.DefaultCounter; -import org.thingsboard.server.common.stats.StatsCounter; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.util.AbstractBufferedRateExecutor; @@ -32,8 +29,6 @@ import org.thingsboard.server.dao.util.AsyncTaskContext; import org.thingsboard.server.dao.util.NoSqlAnyDao; import javax.annotation.PreDestroy; -import java.util.HashMap; -import java.util.Map; /** * Created by ashvayka on 24.10.18. @@ -41,15 +36,11 @@ import java.util.Map; @Component @Slf4j @NoSqlAnyDao -public class CassandraBufferedRateExecutor extends AbstractBufferedRateExecutor { +public class CassandraBufferedRateReadExecutor extends AbstractBufferedRateExecutor { - @Autowired - private EntityService entityService; - private Map tenantNamesCache = new HashMap<>(); + static final String BUFFER_NAME = "Read"; - private boolean printTenantNames; - - public CassandraBufferedRateExecutor( + public CassandraBufferedRateReadExecutor( @Value("${cassandra.query.buffer_size}") int queueLimit, @Value("${cassandra.query.concurrent_limit}") int concurrencyLimit, @Value("${cassandra.query.permit_max_wait_time}") long maxWaitTime, @@ -60,57 +51,16 @@ public class CassandraBufferedRateExecutor extends AbstractBufferedRateExecutor< @Value("${cassandra.query.tenant_rate_limits.configuration}") String tenantRateLimitsConfiguration, @Value("${cassandra.query.tenant_rate_limits.print_tenant_names}") boolean printTenantNames, @Value("${cassandra.query.print_queries_freq:0}") int printQueriesFreq, - @Autowired StatsFactory statsFactory) { - super(queueLimit, concurrencyLimit, maxWaitTime, dispatcherThreads, callbackThreads, pollMs, tenantRateLimitsEnabled, tenantRateLimitsConfiguration, printQueriesFreq, statsFactory); - this.printTenantNames = printTenantNames; + @Autowired StatsFactory statsFactory, + @Autowired EntityService entityService) { + super(queueLimit, concurrencyLimit, maxWaitTime, dispatcherThreads, callbackThreads, pollMs, tenantRateLimitsEnabled, tenantRateLimitsConfiguration, printQueriesFreq, statsFactory, + entityService, printTenantNames); } @Scheduled(fixedDelayString = "${cassandra.query.rate_limit_print_interval_ms}") + @Override public void printStats() { - int queueSize = getQueueSize(); - int rateLimitedTenantsCount = (int) stats.getRateLimitedTenants().values().stream() - .filter(defaultCounter -> defaultCounter.get() > 0) - .count(); - - if (queueSize > 0 - || rateLimitedTenantsCount > 0 - || concurrencyLevel.get() > 0 - || stats.getStatsCounters().stream().anyMatch(counter -> counter.get() > 0) - ) { - StringBuilder statsBuilder = new StringBuilder(); - - statsBuilder.append("queueSize").append(" = [").append(queueSize).append("] "); - stats.getStatsCounters().forEach(counter -> { - statsBuilder.append(counter.getName()).append(" = [").append(counter.get()).append("] "); - }); - statsBuilder.append("totalRateLimitedTenants").append(" = [").append(rateLimitedTenantsCount).append("] "); - statsBuilder.append(CONCURRENCY_LEVEL).append(" = [").append(concurrencyLevel.get()).append("] "); - - stats.getStatsCounters().forEach(StatsCounter::clear); - log.info("Permits {}", statsBuilder); - } - - stats.getRateLimitedTenants().entrySet().stream() - .filter(entry -> entry.getValue().get() > 0) - .forEach(entry -> { - TenantId tenantId = entry.getKey(); - DefaultCounter counter = entry.getValue(); - int rateLimitedRequests = counter.get(); - counter.clear(); - if (printTenantNames) { - String name = tenantNamesCache.computeIfAbsent(tenantId, tId -> { - try { - return entityService.fetchEntityNameAsync(TenantId.SYS_TENANT_ID, tenantId).get(); - } catch (Exception e) { - log.error("[{}] Failed to get tenant name", tenantId, e); - return "N/A"; - } - }); - log.info("[{}][{}] Rate limited requests: {}", tenantId, name, rateLimitedRequests); - } else { - log.info("[{}] Rate limited requests: {}", tenantId, rateLimitedRequests); - } - }); + super.printStats(); } @PreDestroy @@ -118,6 +68,11 @@ public class CassandraBufferedRateExecutor extends AbstractBufferedRateExecutor< super.stop(); } + @Override + public String getBufferName() { + return BUFFER_NAME; + } + @Override protected SettableFuture create() { return SettableFuture.create(); @@ -133,7 +88,7 @@ public class CassandraBufferedRateExecutor extends AbstractBufferedRateExecutor< CassandraStatementTask task = taskCtx.getTask(); return task.executeAsync( statement -> - this.submit(new CassandraStatementTask(task.getTenantId(), task.getSession(), statement)) + this.submit(new CassandraStatementTask(task.getTenantId(), task.getSession(), statement)) ); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateWriteExecutor.java b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateWriteExecutor.java new file mode 100644 index 0000000000..990baa1e2a --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateWriteExecutor.java @@ -0,0 +1,95 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.nosql; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; +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.springframework.stereotype.Component; +import org.thingsboard.server.common.stats.StatsFactory; +import org.thingsboard.server.dao.entity.EntityService; +import org.thingsboard.server.dao.util.AbstractBufferedRateExecutor; +import org.thingsboard.server.dao.util.AsyncTaskContext; +import org.thingsboard.server.dao.util.NoSqlAnyDao; + +import javax.annotation.PreDestroy; + +/** + * Created by ashvayka on 24.10.18. + */ +@Component +@Slf4j +@NoSqlAnyDao +public class CassandraBufferedRateWriteExecutor extends AbstractBufferedRateExecutor { + + static final String BUFFER_NAME = "Write"; + + public CassandraBufferedRateWriteExecutor( + @Value("${cassandra.query.buffer_size}") int queueLimit, + @Value("${cassandra.query.concurrent_limit}") int concurrencyLimit, + @Value("${cassandra.query.permit_max_wait_time}") long maxWaitTime, + @Value("${cassandra.query.dispatcher_threads:2}") int dispatcherThreads, + @Value("${cassandra.query.callback_threads:4}") int callbackThreads, + @Value("${cassandra.query.poll_ms:50}") long pollMs, + @Value("${cassandra.query.tenant_rate_limits.enabled}") boolean tenantRateLimitsEnabled, + @Value("${cassandra.query.tenant_rate_limits.configuration}") String tenantRateLimitsConfiguration, + @Value("${cassandra.query.tenant_rate_limits.print_tenant_names}") boolean printTenantNames, + @Value("${cassandra.query.print_queries_freq:0}") int printQueriesFreq, + @Autowired StatsFactory statsFactory, + @Autowired EntityService entityService) { + super(queueLimit, concurrencyLimit, maxWaitTime, dispatcherThreads, callbackThreads, pollMs, tenantRateLimitsEnabled, tenantRateLimitsConfiguration, printQueriesFreq, statsFactory, + entityService, printTenantNames); + } + + @Scheduled(fixedDelayString = "${cassandra.query.rate_limit_print_interval_ms}") + @Override + public void printStats() { + super.printStats(); + } + + @PreDestroy + public void stop() { + super.stop(); + } + + @Override + public String getBufferName() { + return BUFFER_NAME; + } + + @Override + protected SettableFuture create() { + return SettableFuture.create(); + } + + @Override + protected TbResultSetFuture wrap(CassandraStatementTask task, SettableFuture future) { + return new TbResultSetFuture(future); + } + + @Override + protected ListenableFuture execute(AsyncTaskContext taskCtx) { + CassandraStatementTask task = taskCtx.getTask(); + return task.executeAsync( + statement -> + this.submit(new CassandraStatementTask(task.getTenantId(), task.getSession(), statement)) + ); + } + +} 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 157755db19..d4d86bfb61 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 @@ -31,12 +31,17 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.ThingsBoardExecutors; 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.common.stats.DefaultCounter; +import org.thingsboard.server.common.stats.StatsCounter; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.common.stats.StatsType; -import org.thingsboard.server.common.msg.tools.TbRateLimits; +import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.nosql.CassandraStatementTask; import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; @@ -75,22 +80,32 @@ public abstract class AbstractBufferedRateExecutor tenantNamesCache = new HashMap<>(); + + private final boolean printTenantNames; + public AbstractBufferedRateExecutor(int queueLimit, int concurrencyLimit, long maxWaitTime, int dispatcherThreads, int callbackThreads, long pollMs, - boolean perTenantLimitsEnabled, String perTenantLimitsConfiguration, int printQueriesFreq, StatsFactory statsFactory) { + boolean perTenantLimitsEnabled, String perTenantLimitsConfiguration, int printQueriesFreq, StatsFactory statsFactory, + EntityService entityService, boolean printTenantNames) { this.maxWaitTime = maxWaitTime; this.pollMs = pollMs; this.concurrencyLimit = concurrencyLimit; this.printQueriesFreq = printQueriesFreq; this.queue = new LinkedBlockingDeque<>(queueLimit); - this.dispatcherExecutor = Executors.newFixedThreadPool(dispatcherThreads, ThingsBoardThreadFactory.forName("nosql-dispatcher")); - this.callbackExecutor = ThingsBoardExecutors.newWorkStealingPool(callbackThreads, getClass()); - this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("nosql-timeout")); + this.dispatcherExecutor = Executors.newFixedThreadPool(dispatcherThreads, ThingsBoardThreadFactory.forName("nosql-" + getBufferName() + "-dispatcher")); + this.callbackExecutor = ThingsBoardExecutors.newWorkStealingPool(callbackThreads, "nosql-" + getBufferName() + "-callback"); + this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("nosql-" + getBufferName() + "-timeout")); this.perTenantLimitsEnabled = perTenantLimitsEnabled; this.perTenantLimitsConfiguration = perTenantLimitsConfiguration; this.stats = new BufferedRateExecutorStats(statsFactory); - String concurrencyLevelKey = StatsType.RATE_EXECUTOR.getName() + "." + CONCURRENCY_LEVEL; + String concurrencyLevelKey = StatsType.RATE_EXECUTOR.getName() + "." + CONCURRENCY_LEVEL + getBufferName(); //metric name may change with buffer name suffix this.concurrencyLevel = statsFactory.createGauge(concurrencyLevelKey, new AtomicInteger(0)); + this.entityService = entityService; + this.printTenantNames = printTenantNames; + for (int i = 0; i < dispatcherThreads; i++) { dispatcherExecutor.submit(this::dispatch); } @@ -144,6 +159,8 @@ public abstract class AbstractBufferedRateExecutor execute(AsyncTaskContext taskCtx); + public abstract String getBufferName(); + private void dispatch() { log.info("Buffered rate executor thread started"); while (!Thread.interrupted()) { @@ -264,4 +281,51 @@ public abstract class AbstractBufferedRateExecutor defaultCounter.get() > 0) + .count(); + + if (queueSize > 0 + || rateLimitedTenantsCount > 0 + || concurrencyLevel.get() > 0 + || stats.getStatsCounters().stream().anyMatch(counter -> counter.get() > 0) + ) { + StringBuilder statsBuilder = new StringBuilder(); + + statsBuilder.append("queueSize").append(" = [").append(queueSize).append("] "); + stats.getStatsCounters().forEach(counter -> { + statsBuilder.append(counter.getName()).append(" = [").append(counter.get()).append("] "); + }); + statsBuilder.append("totalRateLimitedTenants").append(" = [").append(rateLimitedTenantsCount).append("] "); + statsBuilder.append(CONCURRENCY_LEVEL).append(" = [").append(concurrencyLevel.get()).append("] "); + + stats.getStatsCounters().forEach(StatsCounter::clear); + log.info("Permits {}", statsBuilder); + } + + stats.getRateLimitedTenants().entrySet().stream() + .filter(entry -> entry.getValue().get() > 0) + .forEach(entry -> { + TenantId tenantId = entry.getKey(); + DefaultCounter counter = entry.getValue(); + int rateLimitedRequests = counter.get(); + counter.clear(); + if (printTenantNames) { + String name = tenantNamesCache.computeIfAbsent(tenantId, tId -> { + try { + return entityService.fetchEntityNameAsync(TenantId.SYS_TENANT_ID, tenantId).get(); + } catch (Exception e) { + log.error("[{}] Failed to get tenant name", tenantId, e); + return "N/A"; + } + }); + log.info("[{}][{}] Rate limited requests: {}", tenantId, name, rateLimitedRequests); + } else { + log.info("[{}] Rate limited requests: {}", tenantId, rateLimitedRequests); + } + }); + } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java index e8eae60131..ef371569dd 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -20,6 +20,7 @@ import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -38,6 +39,7 @@ import java.util.UUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -58,9 +60,6 @@ public class CassandraPartitionsCacheTest { @Mock private Environment environment; - @Mock - private CassandraBufferedRateExecutor rateLimiter; - @Mock private CassandraCluster cluster; @@ -74,7 +73,6 @@ public class CassandraPartitionsCacheTest { ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "systemTtl", 0); ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "setNullValuesEnabled", false); ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "environment", environment); - ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "rateLimiter", rateLimiter); ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "cluster", cluster); when(cluster.getDefaultReadConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); @@ -88,7 +86,9 @@ public class CassandraPartitionsCacheTest { when(boundStatement.setUuid(anyInt(), any(UUID.class))).thenReturn(boundStatement); when(boundStatement.setLong(anyInt(), any(Long.class))).thenReturn(boundStatement); - doReturn(Futures.immediateFuture(0)).when(cassandraBaseTimeseriesDao).getFuture(any(TbResultSetFuture.class), any()); + willReturn(new TbResultSetFuture(SettableFuture.create())).given(cassandraBaseTimeseriesDao).executeAsyncWrite(any(), any()); + + doReturn(Futures.immediateFuture(0)).when(cassandraBaseTimeseriesDao).getFuture(any(), any()); } @Test @@ -107,4 +107,5 @@ public class CassandraPartitionsCacheTest { } verify(cassandraBaseTimeseriesDao, times(60000)).executeAsyncWrite(any(TenantId.class), any(Statement.class)); } + } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index 3474ee2c9d..239c86ed57 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -245,7 +245,9 @@ public interface TbContext { CassandraCluster getCassandraCluster(); - TbResultSetFuture submitCassandraTask(CassandraStatementTask task); + TbResultSetFuture submitCassandraReadTask(CassandraStatementTask task); + + TbResultSetFuture submitCassandraWriteTask(CassandraStatementTask task); PageData findRuleNodeStates(PageLink pageLink); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java index 5cf1a3a7a5..a56cb644be 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java @@ -213,7 +213,7 @@ public class TbSaveToCustomCassandraTableNode implements TbNode { if (statement.getConsistencyLevel() == null) { statement.setConsistencyLevel(level); } - return ctx.submitCassandraTask(new CassandraStatementTask(ctx.getTenantId(), getSession(), statement)); + return ctx.submitCassandraWriteTask(new CassandraStatementTask(ctx.getTenantId(), getSession(), statement)); } private static String statementToString(Statement statement) { From fbdb7bf224645d0f24b33f01e4a8042fdcb4959d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 21 Oct 2021 19:46:24 +0300 Subject: [PATCH 116/303] Move constants to ControllerConstants --- .../server/controller/AdminController.java | 2 + .../server/controller/AlarmController.java | 15 + .../server/controller/AssetController.java | 20 + .../server/controller/AuditLogController.java | 13 + .../server/controller/BaseController.java | 247 +-- .../ComponentDescriptorController.java | 2 + .../controller/ControllerConstants.java | 1332 +++++++++++++++++ .../server/controller/CustomerController.java | 14 + .../controller/DashboardController.java | 23 +- .../server/controller/DeviceController.java | 23 + .../controller/DeviceProfileController.java | 465 +----- .../server/controller/EdgeController.java | 16 + .../controller/EdgeEventController.java | 9 + .../controller/EntityQueryController.java | 627 +------- .../controller/EntityRelationController.java | 5 + .../controller/EntityViewController.java | 5 + .../server/controller/EventController.java | 23 + .../OAuth2ConfigTemplateController.java | 3 + .../server/controller/OAuth2Controller.java | 2 + .../controller/OtaPackageController.java | 16 + .../server/controller/QueueController.java | 4 + .../server/controller/RpcV1Controller.java | 3 + .../server/controller/RpcV2Controller.java | 2 + .../controller/RuleChainController.java | 19 + .../controller/TbResourceController.java | 16 + .../controller/TelemetryController.java | 8 + .../server/controller/TenantController.java | 15 + .../controller/TenantProfileController.java | 2 + .../server/controller/UserController.java | 2 + .../controller/WidgetTypeController.java | 3 +- .../controller/WidgetsBundleController.java | 2 + 31 files changed, 1620 insertions(+), 1318 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java diff --git a/application/src/main/java/org/thingsboard/server/controller/AdminController.java b/application/src/main/java/org/thingsboard/server/controller/AdminController.java index 4284e3ca79..d9a8f436b9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AdminController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AdminController.java @@ -41,6 +41,8 @@ import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.system.SystemSecurityService; import org.thingsboard.server.service.update.UpdateService; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping("/api/admin") diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index b5a892df57..802bc2f93a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -52,6 +52,21 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.List; +import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ALARM_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ALARM_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index 2e3e327ced..f7098868d8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -64,6 +64,26 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.ASSET_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ASSET_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ASSET_NAME_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ASSET_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.ASSET_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ASSET_TYPE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.EdgeController.EDGE_ID; import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; diff --git a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java index 5f71c0950c..70e657d4fc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java @@ -42,6 +42,19 @@ import java.util.List; import java.util.UUID; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.AUDIT_LOG_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.USER_ID_PARAM_DESCRIPTION; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index cd7e89cd6e..0943ef27d1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -147,6 +147,8 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; +import static org.thingsboard.server.controller.ControllerConstants.DEFAULT_PAGE_SIZE; +import static org.thingsboard.server.controller.ControllerConstants.INCORRECT_TENANT_ID; import static org.thingsboard.server.dao.service.Validator.validateId; @Slf4j @@ -155,251 +157,6 @@ public abstract class BaseController { /*Swagger UI description*/ - protected static final String NEW_LINE = "\n\n"; - - public static final String CUSTOMER_ID = "customerId"; - public static final String TENANT_ID = "tenantId"; - public static final String DEVICE_ID = "deviceId"; - public static final String RPC_ID = "rpcId"; - public static final String ENTITY_ID = "entityId"; - public static final String ENTITY_TYPE = "entityType"; - - public static final String PAGE_DATA_PARAMETERS = "You can specify parameters to filter the results. " + - "The result is wrapped with PageData object that allows you to iterate over result set using pagination. " + - "See the 'Model' tab of the Response Class for more details. "; - public static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String RPC_ID_PARAM_DESCRIPTION = "A string value representing the rpc id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String DEVICE_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String TENANT_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the tenant profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String TENANT_ID_PARAM_DESCRIPTION = "A string value representing the tenant id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String EDGE_ID_PARAM_DESCRIPTION = "A string value representing the edge id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String USER_ID_PARAM_DESCRIPTION = "A string value representing the user id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String ASSET_ID_PARAM_DESCRIPTION = "A string value representing the asset id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String ALARM_ID_PARAM_DESCRIPTION = "A string value representing the alarm id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String ENTITY_ID_PARAM_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String OTA_PACKAGE_ID_PARAM_DESCRIPTION = "A string value representing the ota package id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; - public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String WIDGET_TYPE_ID_PARAM_DESCRIPTION = "A string value representing the widget type id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - public static final String RESOURCE_ID_PARAM_DESCRIPTION = "A string value representing the resource id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; - - - protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; - protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; - protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority."; - protected static final String TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; - protected static final String CUSTOMER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'CUSTOMER_USER' authority."; - protected static final String AVAILABLE_FOR_ANY_AUTHORIZED_USER = "\n\nAvailable for any authorized user. "; - - protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; - protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; - protected static final String DEVICE_TYPE_DESCRIPTION = "Device type as the name of the device profile"; - protected static final String ASSET_TYPE_DESCRIPTION = "Asset type"; - protected static final String EDGE_TYPE_DESCRIPTION = "A string value representing the edge type. For example, 'default'"; - protected static final String RULE_CHAIN_TYPE_DESCRIPTION = "Rule chain type (CORE or EDGE)"; - - protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; - protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; - protected static final String WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the widget bundle title."; - protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; - protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; - protected static final String USER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the user email."; - protected static final String TENANT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant name."; - protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant profile name."; - protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name."; - protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name."; - protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; - protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name."; - protected static final String EVENT_TEXT_SEARCH_DESCRIPTION = "The value is not used in searching."; - protected static final String AUDIT_LOG_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on one of the next properties: entityType, entityName, userName, actionType, actionStatus."; - protected static final String SORT_PROPERTY_DESCRIPTION = "Property of entity to sort by"; - protected static final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title"; - protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; - protected static final String RPC_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, expirationTime, request, response"; - protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; - protected static final String USER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, firstName, lastName, email"; - protected static final String TENANT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, state, city, address, address2, zip, phone, email"; - protected static final String TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault"; - protected static final String TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; - protected static final String TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, tenantProfileName, title, email, country, state, city, address, address2, zip, phone, email"; - protected static final String DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, transportType, description, isDefault"; - protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; - protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; - protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; - protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; - protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root"; - protected static final String WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, tenantId"; - protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; - protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; - protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; - protected static final String RPC_STATUS_ALLOWABLE_VALUES = "QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED"; - protected static final String RULE_CHAIN_TYPES_ALLOWABLE_VALUES = "CORE, EDGE"; - protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP"; - protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; - protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; - protected static final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that also contains name of the alarm originator."; - protected static final String RELATION_INFO_DESCRIPTION = "Relation Info is an extension of the default Relation object that contains information about the 'from' and 'to' entity names. "; - protected static final String EDGE_INFO_DESCRIPTION = "Edge Info is an extension of the default Edge object that contains information about the assigned customer name. "; - protected static final String DEVICE_PROFILE_INFO_DESCRIPTION = "Device Profile Info is a lightweight object that includes main information about Device Profile excluding the heavyweight configuration object. "; - protected static final String QUEUE_SERVICE_TYPE_DESCRIPTION = "Service type (implemented only for the TB-RULE-ENGINE)"; - protected static final String QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES = "TB-RULE-ENGINE, TB-CORE, TB-TRANSPORT, JS-EXECUTOR"; - protected static final String OTA_PACKAGE_INFO_DESCRIPTION = "OTA Package Info is a lightweight object that includes main information about the OTA Package excluding the heavyweight data. "; - protected static final String OTA_PACKAGE_DESCRIPTION = "OTA Package is a heavyweight object that includes main information about the OTA Package and also data. "; - protected static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES = "MD5, SHA256, SHA384, SHA512, CRC32, MURMUR3_32, MURMUR3_128"; - protected static final String OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the ota package title."; - protected static final String OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, type, title, version, tag, url, fileName, dataSize, checksum"; - protected static final String RESOURCE_INFO_DESCRIPTION = "Resource Info is a lightweight object that includes main information about the Resource excluding the heavyweight data. "; - protected static final String RESOURCE_DESCRIPTION = "Resource is a heavyweight object that includes main information about the Resource and also data. "; - protected static final String RESOURCE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the resource title."; - protected static final String RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, resourceType, tenantId"; - protected static final String LWM2M_OBJECT_DESCRIPTION = "LwM2M Object is a object that includes information about the LwM2M model which can be used in transport configuration for the LwM2M device profile. "; - protected static final String LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; - - protected static final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; - protected static final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; - - protected static final String EVENT_START_TIME_DESCRIPTION = "Timestamp. Events with creation time before it won't be queried."; - protected static final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; - - protected static final String EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Unassignment works in async way - first, 'unassign' notification event pushed to edge queue on platform. "; - protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; - protected static final String EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Assignment works in async way - first, notification event pushed to edge service queue on platform. "; - protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; - - protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n"; - protected static final String MARKDOWN_CODE_BLOCK_END = "\n```"; - protected static final String EVENT_ERROR_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"ERROR\", \"server\": \"ip-172-31-24-152\", " + - "\"method\": \"onClusterEventMsg\", \"error\": \"Error Message\" }" + MARKDOWN_CODE_BLOCK_END; - protected static final String EVENT_LC_EVENT_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"LC_EVENT\", \"server\": \"ip-172-31-24-152\", \"event\":" + - " \"STARTED\", \"status\": \"Success\", \"error\": \"Error Message\" }" + MARKDOWN_CODE_BLOCK_END; - protected static final String EVENT_STATS_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"STATS\", \"server\": \"ip-172-31-24-152\", \"messagesProcessed\": 10, \"errorsOccurred\": 5 }" + MARKDOWN_CODE_BLOCK_END; - protected static final String DEBUG_FILTER_OBJ = "\"msgDirectionType\": \"IN\", \"server\": \"ip-172-31-24-152\", \"dataSearch\": \"humidity\", " + - "\"metadataSearch\": \"deviceName\", \"entityName\": \"DEVICE\", \"relationType\": \"Success\"," + - " \"entityId\": \"de9d54a0-2b7a-11ec-a3cc-23386423d98f\", \"msgType\": \"POST_TELEMETRY_REQUEST\"," + - " \"isError\": \"false\", \"error\": \"Error Message\" }"; - protected static final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; - protected static final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; - - protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + - "Provides a hint about the data type of the entity field that is defined in the filter key. " + - "The value type impacts the list of possible operations that you may use in the corresponding predicate. For example, you may use 'STARTS_WITH' or 'END_WITH', but you can't use 'GREATER_OR_EQUAL' for string values." + - "The following filter value types and corresponding predicate operations are supported: " + NEW_LINE + - " * 'STRING' - used to filter any 'String' or 'JSON' values. Operations: EQUAL, NOT_EQUAL, STARTS_WITH, ENDS_WITH, CONTAINS, NOT_CONTAINS; \n" + - " * 'NUMERIC' - used for 'Long' and 'Double' values. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n" + - " * 'BOOLEAN' - used for boolean values. Operations: EQUAL, NOT_EQUAL;\n" + - " * 'DATE_TIME' - similar to numeric, transforms value to milliseconds since epoch. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n"; - - protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"schedule\":{\n" + - " \"type\":\"SPECIFIC_TIME\",\n" + - " \"endsOn\":64800000,\n" + - " \"startsOn\":43200000,\n" + - " \"timezone\":\"Europe/Kiev\",\n" + - " \"daysOfWeek\":[\n" + - " 1,\n" + - " 3,\n" + - " 5\n" + - " ]\n" + - " }\n" + - "}" + - MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"schedule\":{\n" + - " \"type\":\"CUSTOM\",\n" + - " \"items\":[\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":1\n" + - " },\n" + - " {\n" + - " \"endsOn\":64800000,\n" + - " \"enabled\":true,\n" + - " \"startsOn\":43200000,\n" + - " \"dayOfWeek\":2\n" + - " },\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":3\n" + - " },\n" + - " {\n" + - " \"endsOn\":57600000,\n" + - " \"enabled\":true,\n" + - " \"startsOn\":36000000,\n" + - " \"dayOfWeek\":4\n" + - " },\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":5\n" + - " },\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":6\n" + - " },\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":7\n" + - " }\n" + - " ],\n" + - " \"timezone\":\"Europe/Kiev\"\n" + - " }\n" + - "}" + - MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "\"schedule\": null" + MARKDOWN_CODE_BLOCK_END; - - protected static final String DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"spec\":{\n" + - " \"type\":\"REPEATING\",\n" + - " \"predicate\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":5,\n" + - " \"dynamicValue\":{\n" + - " \"inherit\":true,\n" + - " \"sourceType\":\"CURRENT_DEVICE\",\n" + - " \"sourceAttribute\":\"tempAttr\"\n" + - " }\n" + - " }\n" + - " }\n" + - "}" + - MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"spec\":{\n" + - " \"type\":\"DURATION\",\n" + - " \"unit\":\"MINUTES\",\n" + - " \"predicate\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":30,\n" + - " \"dynamicValue\":null\n" + - " }\n" + - " }\n" + - "}" + - MARKDOWN_CODE_BLOCK_END; - - protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; - protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; - - public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; - protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; - protected static final String HOME_DASHBOARD = "homeDashboardId"; - - private static final int DEFAULT_PAGE_SIZE = 1000; - private static final ObjectMapper json = new ObjectMapper(); @Autowired diff --git a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java index 0cd657466b..d365d06ca5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java +++ b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java @@ -35,6 +35,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java new file mode 100644 index 0000000000..c63f6178c7 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -0,0 +1,1332 @@ +/** + * Copyright © 2016-2021 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.controller; + +public class ControllerConstants { + + + protected static final String NEW_LINE = "\n\n"; + protected static final int DEFAULT_PAGE_SIZE = 1000; + protected static final String ENTITY_TYPE = "entityType"; + protected static final String CUSTOMER_ID = "customerId"; + protected static final String TENANT_ID = "tenantId"; + protected static final String DEVICE_ID = "deviceId"; + protected static final String RPC_ID = "rpcId"; + protected static final String ENTITY_ID = "entityId"; + protected static final String PAGE_DATA_PARAMETERS = "You can specify parameters to filter the results. " + + "The result is wrapped with PageData object that allows you to iterate over result set using pagination. " + + "See the 'Model' tab of the Response Class for more details. "; + protected static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String RPC_ID_PARAM_DESCRIPTION = "A string value representing the rpc id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String DEVICE_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String TENANT_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the tenant profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String TENANT_ID_PARAM_DESCRIPTION = "A string value representing the tenant id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String EDGE_ID_PARAM_DESCRIPTION = "A string value representing the edge id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String USER_ID_PARAM_DESCRIPTION = "A string value representing the user id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ASSET_ID_PARAM_DESCRIPTION = "A string value representing the asset id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ALARM_ID_PARAM_DESCRIPTION = "A string value representing the alarm id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ENTITY_ID_PARAM_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String OTA_PACKAGE_ID_PARAM_DESCRIPTION = "A string value representing the ota package id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; + protected static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String WIDGET_TYPE_ID_PARAM_DESCRIPTION = "A string value representing the widget type id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String RESOURCE_ID_PARAM_DESCRIPTION = "A string value representing the resource id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; + protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; + protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority."; + protected static final String TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; + protected static final String CUSTOMER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'CUSTOMER_USER' authority."; + protected static final String AVAILABLE_FOR_ANY_AUTHORIZED_USER = "\n\nAvailable for any authorized user. "; + protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; + protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; + protected static final String DEVICE_TYPE_DESCRIPTION = "Device type as the name of the device profile"; + protected static final String ASSET_TYPE_DESCRIPTION = "Asset type"; + protected static final String EDGE_TYPE_DESCRIPTION = "A string value representing the edge type. For example, 'default'"; + protected static final String RULE_CHAIN_TYPE_DESCRIPTION = "Rule chain type (CORE or EDGE)"; + protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; + protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; + protected static final String WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the widget bundle title."; + protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; + protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; + protected static final String USER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the user email."; + protected static final String TENANT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant name."; + protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant profile name."; + protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name."; + protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name."; + protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; + protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name."; + protected static final String EVENT_TEXT_SEARCH_DESCRIPTION = "The value is not used in searching."; + protected static final String AUDIT_LOG_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on one of the next properties: entityType, entityName, userName, actionType, actionStatus."; + protected static final String SORT_PROPERTY_DESCRIPTION = "Property of entity to sort by"; + protected static final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title"; + protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; + protected static final String RPC_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, expirationTime, request, response"; + protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; + protected static final String USER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, firstName, lastName, email"; + protected static final String TENANT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, state, city, address, address2, zip, phone, email"; + protected static final String TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault"; + protected static final String TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; + protected static final String TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, tenantProfileName, title, email, country, state, city, address, address2, zip, phone, email"; + protected static final String DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, transportType, description, isDefault"; + protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; + protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; + protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; + protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; + protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root"; + protected static final String WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, tenantId"; + protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; + protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; + protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; + protected static final String RPC_STATUS_ALLOWABLE_VALUES = "QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED"; + protected static final String RULE_CHAIN_TYPES_ALLOWABLE_VALUES = "CORE, EDGE"; + protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP"; + protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; + protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; + protected static final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that also contains name of the alarm originator."; + protected static final String RELATION_INFO_DESCRIPTION = "Relation Info is an extension of the default Relation object that contains information about the 'from' and 'to' entity names. "; + protected static final String EDGE_INFO_DESCRIPTION = "Edge Info is an extension of the default Edge object that contains information about the assigned customer name. "; + protected static final String DEVICE_PROFILE_INFO_DESCRIPTION = "Device Profile Info is a lightweight object that includes main information about Device Profile excluding the heavyweight configuration object. "; + protected static final String QUEUE_SERVICE_TYPE_DESCRIPTION = "Service type (implemented only for the TB-RULE-ENGINE)"; + protected static final String QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES = "TB-RULE-ENGINE, TB-CORE, TB-TRANSPORT, JS-EXECUTOR"; + protected static final String OTA_PACKAGE_INFO_DESCRIPTION = "OTA Package Info is a lightweight object that includes main information about the OTA Package excluding the heavyweight data. "; + protected static final String OTA_PACKAGE_DESCRIPTION = "OTA Package is a heavyweight object that includes main information about the OTA Package and also data. "; + protected static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES = "MD5, SHA256, SHA384, SHA512, CRC32, MURMUR3_32, MURMUR3_128"; + protected static final String OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the ota package title."; + protected static final String OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, type, title, version, tag, url, fileName, dataSize, checksum"; + protected static final String RESOURCE_INFO_DESCRIPTION = "Resource Info is a lightweight object that includes main information about the Resource excluding the heavyweight data. "; + protected static final String RESOURCE_DESCRIPTION = "Resource is a heavyweight object that includes main information about the Resource and also data. "; + + protected static final String RESOURCE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the resource title."; + protected static final String RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, resourceType, tenantId"; + protected static final String LWM2M_OBJECT_DESCRIPTION = "LwM2M Object is a object that includes information about the LwM2M model which can be used in transport configuration for the LwM2M device profile. "; + protected static final String LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; + + protected static final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name."; + protected static final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name."; + + protected static final String EVENT_START_TIME_DESCRIPTION = "Timestamp. Events with creation time before it won't be queried."; + protected static final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; + + protected static final String EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Unassignment works in async way - first, 'unassign' notification event pushed to edge queue on platform. "; + protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; + protected static final String EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Assignment works in async way - first, notification event pushed to edge service queue on platform. "; + protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; + + protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n"; + protected static final String MARKDOWN_CODE_BLOCK_END = "\n```"; + protected static final String EVENT_ERROR_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"ERROR\", \"server\": \"ip-172-31-24-152\", " + + "\"method\": \"onClusterEventMsg\", \"error\": \"Error Message\" }" + MARKDOWN_CODE_BLOCK_END; + protected static final String EVENT_LC_EVENT_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"LC_EVENT\", \"server\": \"ip-172-31-24-152\", \"event\":" + + " \"STARTED\", \"status\": \"Success\", \"error\": \"Error Message\" }" + MARKDOWN_CODE_BLOCK_END; + protected static final String EVENT_STATS_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"STATS\", \"server\": \"ip-172-31-24-152\", \"messagesProcessed\": 10, \"errorsOccurred\": 5 }" + MARKDOWN_CODE_BLOCK_END; + protected static final String DEBUG_FILTER_OBJ = "\"msgDirectionType\": \"IN\", \"server\": \"ip-172-31-24-152\", \"dataSearch\": \"humidity\", " + + "\"metadataSearch\": \"deviceName\", \"entityName\": \"DEVICE\", \"relationType\": \"Success\"," + + " \"entityId\": \"de9d54a0-2b7a-11ec-a3cc-23386423d98f\", \"msgType\": \"POST_TELEMETRY_REQUEST\"," + + " \"isError\": \"false\", \"error\": \"Error Message\" }"; + protected static final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; + protected static final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; + + protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + + "Provides a hint about the data type of the entity field that is defined in the filter key. " + + "The value type impacts the list of possible operations that you may use in the corresponding predicate. For example, you may use 'STARTS_WITH' or 'END_WITH', but you can't use 'GREATER_OR_EQUAL' for string values." + + "The following filter value types and corresponding predicate operations are supported: " + NEW_LINE + + " * 'STRING' - used to filter any 'String' or 'JSON' values. Operations: EQUAL, NOT_EQUAL, STARTS_WITH, ENDS_WITH, CONTAINS, NOT_CONTAINS; \n" + + " * 'NUMERIC' - used for 'Long' and 'Double' values. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n" + + " * 'BOOLEAN' - used for boolean values. Operations: EQUAL, NOT_EQUAL;\n" + + " * 'DATE_TIME' - similar to numeric, transforms value to milliseconds since epoch. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n"; + + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"schedule\":{\n" + + " \"type\":\"SPECIFIC_TIME\",\n" + + " \"endsOn\":64800000,\n" + + " \"startsOn\":43200000,\n" + + " \"timezone\":\"Europe/Kiev\",\n" + + " \"daysOfWeek\":[\n" + + " 1,\n" + + " 3,\n" + + " 5\n" + + " ]\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"schedule\":{\n" + + " \"type\":\"CUSTOM\",\n" + + " \"items\":[\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":1\n" + + " },\n" + + " {\n" + + " \"endsOn\":64800000,\n" + + " \"enabled\":true,\n" + + " \"startsOn\":43200000,\n" + + " \"dayOfWeek\":2\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":3\n" + + " },\n" + + " {\n" + + " \"endsOn\":57600000,\n" + + " \"enabled\":true,\n" + + " \"startsOn\":36000000,\n" + + " \"dayOfWeek\":4\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":5\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":6\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":7\n" + + " }\n" + + " ],\n" + + " \"timezone\":\"Europe/Kiev\"\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "\"schedule\": null" + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"spec\":{\n" + + " \"type\":\"REPEATING\",\n" + + " \"predicate\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":5,\n" + + " \"dynamicValue\":{\n" + + " \"inherit\":true,\n" + + " \"sourceType\":\"CURRENT_DEVICE\",\n" + + " \"sourceAttribute\":\"tempAttr\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"spec\":{\n" + + " \"type\":\"DURATION\",\n" + + " \"unit\":\"MINUTES\",\n" + + " \"predicate\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":30,\n" + + " \"dynamicValue\":null\n" + + " }\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + + protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value."; + protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'"; + + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; + protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; + protected static final String HOME_DASHBOARD = "homeDashboardId"; + + protected static final String SINGLE_ENTITY = "\n\n## Single Entity\n\n" + + "Allows to filter only one entity based on the id. For example, this entity filter selects certain device:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"singleEntity\",\n" + + " \"singleEntity\": {\n" + + " \"id\": \"d521edb0-2a7a-11ec-94eb-213c95f54092\",\n" + + " \"entityType\": \"DEVICE\"\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String ENTITY_LIST = "\n\n## Entity List Filter\n\n" + + "Allows to filter entities of the same type using their ids. For example, this entity filter selects two devices:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityList\",\n" + + " \"entityType\": \"DEVICE\",\n" + + " \"entityList\": [\n" + + " \"e6501f30-2a7a-11ec-94eb-213c95f54092\",\n" + + " \"e6657bf0-2a7a-11ec-94eb-213c95f54092\"\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String ENTITY_NAME = "\n\n## Entity Name Filter\n\n" + + "Allows to filter entities of the same type using the **'starts with'** expression over entity name. " + + "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityName\",\n" + + " \"entityType\": \"DEVICE\",\n" + + " \"entityNameFilter\": \"Air Quality\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String ENTITY_TYPE_FILTER = "\n\n## Entity Type Filter\n\n" + + "Allows to filter entities based on their type (CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, etc)" + + "For example, this entity filter selects all tenant customers:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityType\",\n" + + " \"entityType\": \"CUSTOMER\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String ASSET_TYPE = "\n\n## Asset Type Filter\n\n" + + "Allows to filter assets based on their type and the **'starts with'** expression over their name. " + + "For example, this entity filter selects all 'charging station' assets which name starts with 'Tesla':\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"assetType\",\n" + + " \"assetType\": \"charging station\",\n" + + " \"assetNameFilter\": \"Tesla\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String DEVICE_TYPE = "\n\n## Device Type Filter\n\n" + + "Allows to filter devices based on their type and the **'starts with'** expression over their name. " + + "For example, this entity filter selects all 'Temperature Sensor' devices which name starts with 'ABC':\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"deviceType\",\n" + + " \"deviceType\": \"Temperature Sensor\",\n" + + " \"deviceNameFilter\": \"ABC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String EDGE_TYPE = "\n\n## Edge Type Filter\n\n" + + "Allows to filter edge instances based on their type and the **'starts with'** expression over their name. " + + "For example, this entity filter selects all 'Factory' edge instances which name starts with 'Nevada':\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"edgeType\",\n" + + " \"edgeType\": \"Factory\",\n" + + " \"edgeNameFilter\": \"Nevada\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String ENTITY_VIEW_TYPE = "\n\n## Entity View Filter\n\n" + + "Allows to filter entity views based on their type and the **'starts with'** expression over their name. " + + "For example, this entity filter selects all 'Concrete Mixer' entity views which name starts with 'CAT':\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityViewType\",\n" + + " \"entityViewType\": \"Concrete Mixer\",\n" + + " \"entityViewNameFilter\": \"CAT\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String API_USAGE = "\n\n## Api Usage Filter\n\n" + + "Allows to query for Api Usage based on optional customer id. If the customer id is not set, returns current tenant API usage." + + "For example, this entity filter selects the 'Api Usage' entity for customer with id 'e6501f30-2a7a-11ec-94eb-213c95f54092':\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"apiUsageState\",\n" + + " \"customerId\": {\n" + + " \"id\": \"d521edb0-2a7a-11ec-94eb-213c95f54092\",\n" + + " \"entityType\": \"CUSTOMER\"\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String MAX_LEVEL_DESCRIPTION = "Possible direction values are 'TO' and 'FROM'. The 'maxLevel' defines how many relation levels should the query search 'recursively'. "; + protected static final String FETCH_LAST_LEVEL_ONLY_DESCRIPTION = "Assuming the 'maxLevel' is > 1, the 'fetchLastLevelOnly' defines either to return all related entities or only entities that are on the last level of relations. "; + + protected static final String RELATIONS_QUERY_FILTER = "\n\n## Relations Query Filter\n\n" + + "Allows to filter entities that are related to the provided root entity. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'filter' object allows you to define the relation type and set of acceptable entity types to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only those who match the 'filters'.\n\n" + + "For example, this entity filter selects all devices and assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092':\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"relationsQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e51de0c0-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 1,\n" + + " \"fetchLastLevelOnly\": false,\n" + + " \"filters\": [\n" + + " {\n" + + " \"relationType\": \"Contains\",\n" + + " \"entityTypes\": [\n" + + " \"DEVICE\",\n" + + " \"ASSET\"\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + + protected static final String ASSET_QUERY_FILTER = "\n\n## Asset Search Query\n\n" + + "Allows to filter assets that are related to the provided root entity. Filters related assets based on the relation type and set of asset types. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'relationType' defines the type of the relation to search for. " + + "The 'assetTypes' defines the type of the asset to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only assets that match 'relationType' and 'assetTypes' conditions.\n\n" + + "For example, this entity filter selects 'charging station' assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"assetSearchQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e51de0c0-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 1,\n" + + " \"fetchLastLevelOnly\": false,\n" + + " \"relationType\": \"Contains\",\n" + + " \"assetTypes\": [\n" + + " \"charging station\"\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String DEVICE_QUERY_FILTER = "\n\n## Device Search Query\n\n" + + "Allows to filter devices that are related to the provided root entity. Filters related devices based on the relation type and set of device types. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'relationType' defines the type of the relation to search for. " + + "The 'deviceTypes' defines the type of the device to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + + "For example, this entity filter selects 'Charging port' and 'Air Quality Sensor' devices which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"deviceSearchQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 2,\n" + + " \"fetchLastLevelOnly\": true,\n" + + " \"relationType\": \"Contains\",\n" + + " \"deviceTypes\": [\n" + + " \"Air Quality Sensor\",\n" + + " \"Charging port\"\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String EV_QUERY_FILTER = "\n\n## Entity View Query\n\n" + + "Allows to filter entity views that are related to the provided root entity. Filters related entity views based on the relation type and set of entity view types. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'relationType' defines the type of the relation to search for. " + + "The 'entityViewTypes' defines the type of the entity view to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + + "For example, this entity filter selects 'Concrete mixer' entity views which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"entityViewSearchQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 1,\n" + + " \"fetchLastLevelOnly\": false,\n" + + " \"relationType\": \"Contains\",\n" + + " \"entityViewTypes\": [\n" + + " \"Concrete mixer\"\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String EDGE_QUERY_FILTER = "\n\n## Edge Search Query\n\n" + + "Allows to filter edge instances that are related to the provided root entity. Filters related edge instances based on the relation type and set of edge types. " + + MAX_LEVEL_DESCRIPTION + + FETCH_LAST_LEVEL_ONLY_DESCRIPTION + + "The 'relationType' defines the type of the relation to search for. " + + "The 'deviceTypes' defines the type of the device to search for. " + + "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + + "For example, this entity filter selects 'Factory' edge instances which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"deviceSearchQuery\",\n" + + " \"rootEntity\": {\n" + + " \"entityType\": \"ASSET\",\n" + + " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + + " },\n" + + " \"direction\": \"FROM\",\n" + + " \"maxLevel\": 2,\n" + + " \"fetchLastLevelOnly\": true,\n" + + " \"relationType\": \"Contains\",\n" + + " \"edgeTypes\": [\n" + + " \"Factory\"\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String EMPTY = "\n\n## Entity Type Filter\n\n" + + "Allows to filter multiple entities of the same type using the **'starts with'** expression over entity name. " + + "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n" + + MARKDOWN_CODE_BLOCK_START + + "" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String ENTITY_FILTERS = + "\n\n # Entity Filters" + + "\nEntity Filter body depends on the 'type' parameter. Let's review available entity filter types. In fact, they do correspond to available dashboard aliases." + + SINGLE_ENTITY + ENTITY_LIST + ENTITY_NAME + ENTITY_TYPE_FILTER + ASSET_TYPE + DEVICE_TYPE + EDGE_TYPE + ENTITY_VIEW_TYPE + API_USAGE + RELATIONS_QUERY_FILTER + + ASSET_QUERY_FILTER + DEVICE_QUERY_FILTER + EV_QUERY_FILTER + EDGE_QUERY_FILTER; + + protected static final String FILTER_KEY = "\n\n## Filter Key\n\n" + + "Filter Key defines either entity field, attribute or telemetry. It is a JSON object that consists the key name and type. " + + "The following filter key types are supported: \n\n" + + " * 'CLIENT_ATTRIBUTE' - used for client attributes; \n" + + " * 'SHARED_ATTRIBUTE' - used for shared attributes; \n" + + " * 'SERVER_ATTRIBUTE' - used for server attributes; \n" + + " * 'ATTRIBUTE' - used for any of the above; \n" + + " * 'TIME_SERIES' - used for time-series values; \n" + + " * 'ENTITY_FIELD' - used for accessing entity fields like 'name', 'label', etc. The list of available fields depends on the entity type; \n" + + " * 'ALARM_FIELD' - similar to entity field, but is used in alarm queries only; \n" + + "\n\n Let's review the example:\n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String FILTER_PREDICATE = "\n\n## Filter Predicate\n\n" + + "Filter Predicate defines the logical expression to evaluate. The list of available operations depends on the filter value type, see above. " + + "Platform supports 4 predicate types: 'STRING', 'NUMERIC', 'BOOLEAN' and 'COMPLEX'. The last one allows to combine multiple operations over one filter key." + + "\n\nSimple predicate example to check 'value < 100': \n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 100,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\nComplex predicate example, to check 'value < 10 or value > 20': \n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"OR\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 10,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 20,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\nMore complex predicate example, to check 'value < 10 or (value > 50 && value < 60)': \n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"OR\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 10,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"AND\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 50,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 60,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n You may also want to replace hardcoded values (for example, temperature > 20) with the more dynamic " + + "expression (for example, temperature > 'value of the tenant attribute with key 'temperatureThreshold'). " + + "It is possible to use 'dynamicValue' to define attribute of the tenant, customer or user that is performing the API call. " + + "See example below: \n\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 0,\n" + + " \"dynamicValue\": {\n" + + " \"sourceType\": \"CURRENT_USER\",\n" + + " \"sourceAttribute\": \"temperatureThreshold\"\n" + + " }\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n Note that you may use 'CURRENT_USER', 'CURRENT_CUSTOMER' and 'CURRENT_TENANT' as a 'sourceType'. The 'defaultValue' is used when the attribute with such a name is not defined for the chosen source."; + + protected static final String KEY_FILTERS = + "\n\n # Key Filters" + + "\nKey Filter allows you to define complex logical expressions over entity field, attribute or latest time-series value. The filter is defined using 'key', 'valueType' and 'predicate' objects. " + + "Single Entity Query may have zero, one or multiple predicates. If multiple filters are defined, they are evaluated using logical 'AND'. " + + "The example below checks that temperature of the entity is above 20 degrees:" + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"key\": {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " },\n" + + " \"valueType\": \"NUMERIC\",\n" + + " \"predicate\": {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 20,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n Now let's review 'key', 'valueType' and 'predicate' objects in detail." + + FILTER_KEY + FILTER_VALUE_TYPE + FILTER_PREDICATE; + + protected static final String ENTITY_COUNT_QUERY_DESCRIPTION = + "Allows to run complex queries to search the count of platform entities (devices, assets, customers, etc) " + + "based on the combination of main entity filter and multiple key filters. Returns the number of entities that match the query definition.\n\n" + + "# Query Definition\n\n" + + "\n\nMain **entity filter** is mandatory and defines generic search criteria. " + + "For example, \"find all devices with profile 'Moisture Sensor'\" or \"Find all devices related to asset 'Building A'\"" + + "\n\nOptional **key filters** allow to filter results of the entity filter by complex criteria against " + + "main entity fields (name, label, type, etc), attributes and telemetry. " + + "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"." + + "\n\nLet's review the example:" + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"entityFilter\": {\n" + + " \"type\": \"entityType\",\n" + + " \"entityType\": \"DEVICE\"\n" + + " },\n" + + " \"keyFilters\": [\n" + + " {\n" + + " \"key\": {\n" + + " \"type\": \"ATTRIBUTE\",\n" + + " \"key\": \"active\"\n" + + " },\n" + + " \"valueType\": \"BOOLEAN\",\n" + + " \"predicate\": {\n" + + " \"operation\": \"EQUAL\",\n" + + " \"value\": {\n" + + " \"defaultValue\": true,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"BOOLEAN\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + + ENTITY_FILTERS + + KEY_FILTERS + + ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + + protected static final String ENTITY_DATA_QUERY_DESCRIPTION = + "Allows to run complex queries over platform entities (devices, assets, customers, etc) " + + "based on the combination of main entity filter and multiple key filters. " + + "Returns the paginated result of the query that contains requested entity fields and latest values of requested attributes and time-series data.\n\n" + + "# Query Definition\n\n" + + "\n\nMain **entity filter** is mandatory and defines generic search criteria. " + + "For example, \"find all devices with profile 'Moisture Sensor'\" or \"Find all devices related to asset 'Building A'\"" + + "\n\nOptional **key filters** allow to filter results of the **entity filter** by complex criteria against " + + "main entity fields (name, label, type, etc), attributes and telemetry. " + + "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"." + + "\n\nThe **entity fields** and **latest values** contains list of entity fields and latest attribute/telemetry fields to fetch for each entity." + + "\n\nThe **page link** contains information about the page to fetch and the sort ordering." + + "\n\nLet's review the example:" + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"entityFilter\": {\n" + + " \"type\": \"entityType\",\n" + + " \"resolveMultiple\": true,\n" + + " \"entityType\": \"DEVICE\"\n" + + " },\n" + + " \"keyFilters\": [\n" + + " {\n" + + " \"key\": {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " },\n" + + " \"valueType\": \"NUMERIC\",\n" + + " \"predicate\": {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 0,\n" + + " \"dynamicValue\": {\n" + + " \"sourceType\": \"CURRENT_USER\",\n" + + " \"sourceAttribute\": \"temperatureThreshold\",\n" + + " \"inherit\": false\n" + + " }\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"entityFields\": [\n" + + " {\n" + + " \"type\": \"ENTITY_FIELD\",\n" + + " \"key\": \"name\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ENTITY_FIELD\",\n" + + " \"key\": \"label\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ENTITY_FIELD\",\n" + + " \"key\": \"additionalInfo\"\n" + + " }\n" + + " ],\n" + + " \"latestValues\": [\n" + + " {\n" + + " \"type\": \"ATTRIBUTE\",\n" + + " \"key\": \"model\"\n" + + " },\n" + + " {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " }\n" + + " ],\n" + + " \"pageLink\": {\n" + + " \"page\": 0,\n" + + " \"pageSize\": 10,\n" + + " \"sortOrder\": {\n" + + " \"key\": {\n" + + " \"key\": \"name\",\n" + + " \"type\": \"ENTITY_FIELD\"\n" + + " },\n" + + " \"direction\": \"ASC\"\n" + + " }\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + + ENTITY_FILTERS + + KEY_FILTERS + + ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + + + protected static final String ALARM_DATA_QUERY_DESCRIPTION = "This method description defines how Alarm Data Query extends the Entity Data Query. " + + "See method 'Find Entity Data by Query' first to get the info about 'Entity Data Query'." + + "\n\n The platform will first search the entities that match the entity and key filters. Then, the platform will use 'Alarm Page Link' to filter the alarms related to those entities. " + + "Finally, platform fetch the properties of alarm that are defined in the **'alarmFields'** and combine them with the other entity, attribute and latest time-series fields to return the result. " + + "\n\n See example of the alarm query below. The query will search first 100 active alarms with type 'Temperature Alarm' or 'Fire Alarm' for any device with current temperature > 0. " + + "The query will return combination of the entity fields: name of the device, device model and latest temperature reading and alarms fields: createdTime, type, severity and status: " + + "\n\n" + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"entityFilter\": {\n" + + " \"type\": \"entityType\",\n" + + " \"resolveMultiple\": true,\n" + + " \"entityType\": \"DEVICE\"\n" + + " },\n" + + " \"pageLink\": {\n" + + " \"page\": 0,\n" + + " \"pageSize\": 100,\n" + + " \"textSearch\": null,\n" + + " \"searchPropagatedAlarms\": false,\n" + + " \"statusList\": [\n" + + " \"ACTIVE\"\n" + + " ],\n" + + " \"severityList\": [\n" + + " \"CRITICAL\",\n" + + " \"MAJOR\"\n" + + " ],\n" + + " \"typeList\": [\n" + + " \"Temperature Alarm\",\n" + + " \"Fire Alarm\"\n" + + " ],\n" + + " \"sortOrder\": {\n" + + " \"key\": {\n" + + " \"key\": \"createdTime\",\n" + + " \"type\": \"ALARM_FIELD\"\n" + + " },\n" + + " \"direction\": \"DESC\"\n" + + " },\n" + + " \"timeWindow\": 86400000\n" + + " },\n" + + " \"keyFilters\": [\n" + + " {\n" + + " \"key\": {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " },\n" + + " \"valueType\": \"NUMERIC\",\n" + + " \"predicate\": {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"defaultValue\": 0,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"alarmFields\": [\n" + + " {\n" + + " \"type\": \"ALARM_FIELD\",\n" + + " \"key\": \"createdTime\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ALARM_FIELD\",\n" + + " \"key\": \"type\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ALARM_FIELD\",\n" + + " \"key\": \"severity\"\n" + + " },\n" + + " {\n" + + " \"type\": \"ALARM_FIELD\",\n" + + " \"key\": \"status\"\n" + + " }\n" + + " ],\n" + + " \"entityFields\": [\n" + + " {\n" + + " \"type\": \"ENTITY_FIELD\",\n" + + " \"key\": \"name\"\n" + + " }\n" + + " ],\n" + + " \"latestValues\": [\n" + + " {\n" + + " \"type\": \"ATTRIBUTE\",\n" + + " \"key\": \"model\"\n" + + " },\n" + + " {\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + ""; + + protected static final String COAP_TRANSPORT_CONFIGURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\":\"COAP\",\n" + + " \"clientSettings\":{\n" + + " \"edrxCycle\":null,\n" + + " \"powerMode\":\"DRX\",\n" + + " \"psmActivityTimer\":null,\n" + + " \"pagingTransmissionWindow\":null\n" + + " },\n" + + " \"coapDeviceTypeConfiguration\":{\n" + + " \"coapDeviceType\":\"DEFAULT\",\n" + + " \"transportPayloadTypeConfiguration\":{\n" + + " \"transportPayloadType\":\"JSON\"\n" + + " }\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + + protected static final String TRANSPORT_CONFIGURATION = "# Transport Configuration" + NEW_LINE + + "5 transport configuration types are available:\n" + + " * 'DEFAULT';\n" + + " * 'MQTT';\n" + + " * 'LWM2M';\n" + + " * 'COAP';\n" + + " * 'SNMP'." + NEW_LINE + "Default type supports basic MQTT, HTTP, CoAP and LwM2M transports. " + + "Please refer to the [docs](https://thingsboard.io/docs/user-guide/device-profiles/#transport-configuration) for more details about other types.\n" + + "\nSee another example of COAP transport configuration below:" + NEW_LINE + COAP_TRANSPORT_CONFIGURATION_EXAMPLE; + + protected static final String ALARM_FILTER_KEY = "## Alarm Filter Key" + NEW_LINE + + "Filter Key defines either entity field, attribute, telemetry or constant. It is a JSON object that consists the key name and type. The following filter key types are supported:\n" + + " * 'ATTRIBUTE' - used for attributes values;\n" + + " * 'TIME_SERIES' - used for time-series values;\n" + + " * 'ENTITY_FIELD' - used for accessing entity fields like 'name', 'label', etc. The list of available fields depends on the entity type;\n" + + " * 'CONSTANT' - constant value specified." + NEW_LINE + "Let's review the example:" + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"TIME_SERIES\",\n" + + " \"key\": \"temperature\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_PROFILE_FILTER_PREDICATE = NEW_LINE + "## Filter Predicate" + NEW_LINE + + "Filter Predicate defines the logical expression to evaluate. The list of available operations depends on the filter value type, see above. " + + "Platform supports 4 predicate types: 'STRING', 'NUMERIC', 'BOOLEAN' and 'COMPLEX'. The last one allows to combine multiple operations over one filter key." + NEW_LINE + + "Simple predicate example to check 'value < 100': " + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 100,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + NEW_LINE + + "Complex predicate example, to check 'value < 10 or value > 20': " + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"OR\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 10,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 20,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + NEW_LINE + + "More complex predicate example, to check 'value < 10 or (value > 50 && value < 60)': " + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"OR\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 10,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"type\": \"COMPLEX\",\n" + + " \"operation\": \"AND\",\n" + + " \"predicates\": [\n" + + " {\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 50,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " },\n" + + " {\n" + + " \"operation\": \"LESS\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 60,\n" + + " \"dynamicValue\": null\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + NEW_LINE + + "You may also want to replace hardcoded values (for example, temperature > 20) with the more dynamic " + + "expression (for example, temperature > value of the tenant attribute with key 'temperatureThreshold'). " + + "It is possible to use 'dynamicValue' to define attribute of the tenant, customer or device. " + + "See example below:" + NEW_LINE + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"operation\": \"GREATER\",\n" + + " \"value\": {\n" + + " \"userValue\": null,\n" + + " \"defaultValue\": 0,\n" + + " \"dynamicValue\": {\n" + + " \"inherit\": false,\n" + + " \"sourceType\": \"CURRENT_TENANT\",\n" + + " \"sourceAttribute\": \"temperatureThreshold\"\n" + + " }\n" + + " },\n" + + " \"type\": \"NUMERIC\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + NEW_LINE + + "Note that you may use 'CURRENT_DEVICE', 'CURRENT_CUSTOMER' and 'CURRENT_TENANT' as a 'sourceType'. The 'defaultValue' is used when the attribute with such a name is not defined for the chosen source. " + + "The 'sourceAttribute' can be inherited from the owner of the specified 'sourceType' if 'inherit' is set to true."; + + protected static final String KEY_FILTERS_DESCRIPTION = "# Key Filters" + NEW_LINE + + "Key filter objects are created under the **'condition'** array. They allow you to define complex logical expressions over entity field, " + + "attribute, latest time-series value or constant. The filter is defined using 'key', 'valueType', " + + "'value' (refers to the value of the 'CONSTANT' alarm filter key type) and 'predicate' objects. Let's review each object:" + NEW_LINE + + ALARM_FILTER_KEY + FILTER_VALUE_TYPE + NEW_LINE + DEVICE_PROFILE_FILTER_PREDICATE + NEW_LINE; + + protected static final String DEFAULT_DEVICE_PROFILE_DATA_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + + " \"alarms\":[\n" + + " ],\n" + + " \"configuration\":{\n" + + " \"type\":\"DEFAULT\"\n" + + " },\n" + + " \"provisionConfiguration\":{\n" + + " \"type\":\"DISABLED\",\n" + + " \"provisionDeviceSecret\":null\n" + + " },\n" + + " \"transportConfiguration\":{\n" + + " \"type\":\"DEFAULT\"\n" + + " }\n" + + "}" + MARKDOWN_CODE_BLOCK_END; + + protected static final String CUSTOM_DEVICE_PROFILE_DATA_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + + " \"alarms\":[\n" + + " {\n" + + " \"id\":\"2492b935-1226-59e9-8615-17d8978a4f93\",\n" + + " \"alarmType\":\"Temperature Alarm\",\n" + + " \"clearRule\":{\n" + + " \"schedule\":null,\n" + + " \"condition\":{\n" + + " \"spec\":{\n" + + " \"type\":\"SIMPLE\"\n" + + " },\n" + + " \"condition\":[\n" + + " {\n" + + " \"key\":{\n" + + " \"key\":\"temperature\",\n" + + " \"type\":\"TIME_SERIES\"\n" + + " },\n" + + " \"value\":null,\n" + + " \"predicate\":{\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":30.0,\n" + + " \"dynamicValue\":null\n" + + " },\n" + + " \"operation\":\"LESS\"\n" + + " },\n" + + " \"valueType\":\"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"dashboardId\":null,\n" + + " \"alarmDetails\":null\n" + + " },\n" + + " \"propagate\":false,\n" + + " \"createRules\":{\n" + + " \"MAJOR\":{\n" + + " \"schedule\":{\n" + + " \"type\":\"SPECIFIC_TIME\",\n" + + " \"endsOn\":64800000,\n" + + " \"startsOn\":43200000,\n" + + " \"timezone\":\"Europe/Kiev\",\n" + + " \"daysOfWeek\":[\n" + + " 1,\n" + + " 3,\n" + + " 5\n" + + " ]\n" + + " },\n" + + " \"condition\":{\n" + + " \"spec\":{\n" + + " \"type\":\"DURATION\",\n" + + " \"unit\":\"MINUTES\",\n" + + " \"predicate\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":30,\n" + + " \"dynamicValue\":null\n" + + " }\n" + + " },\n" + + " \"condition\":[\n" + + " {\n" + + " \"key\":{\n" + + " \"key\":\"temperature\",\n" + + " \"type\":\"TIME_SERIES\"\n" + + " },\n" + + " \"value\":null,\n" + + " \"predicate\":{\n" + + " \"type\":\"COMPLEX\",\n" + + " \"operation\":\"OR\",\n" + + " \"predicates\":[\n" + + " {\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":50.0,\n" + + " \"dynamicValue\":null\n" + + " },\n" + + " \"operation\":\"LESS_OR_EQUAL\"\n" + + " },\n" + + " {\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":30.0,\n" + + " \"dynamicValue\":null\n" + + " },\n" + + " \"operation\":\"GREATER\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"valueType\":\"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"dashboardId\":null,\n" + + " \"alarmDetails\":null\n" + + " },\n" + + " \"WARNING\":{\n" + + " \"schedule\":{\n" + + " \"type\":\"CUSTOM\",\n" + + " \"items\":[\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":1\n" + + " },\n" + + " {\n" + + " \"endsOn\":64800000,\n" + + " \"enabled\":true,\n" + + " \"startsOn\":43200000,\n" + + " \"dayOfWeek\":2\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":3\n" + + " },\n" + + " {\n" + + " \"endsOn\":57600000,\n" + + " \"enabled\":true,\n" + + " \"startsOn\":36000000,\n" + + " \"dayOfWeek\":4\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":5\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":6\n" + + " },\n" + + " {\n" + + " \"endsOn\":0,\n" + + " \"enabled\":false,\n" + + " \"startsOn\":0,\n" + + " \"dayOfWeek\":7\n" + + " }\n" + + " ],\n" + + " \"timezone\":\"Europe/Kiev\"\n" + + " },\n" + + " \"condition\":{\n" + + " \"spec\":{\n" + + " \"type\":\"REPEATING\",\n" + + " \"predicate\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":5,\n" + + " \"dynamicValue\":null\n" + + " }\n" + + " },\n" + + " \"condition\":[\n" + + " {\n" + + " \"key\":{\n" + + " \"key\":\"tempConstant\",\n" + + " \"type\":\"CONSTANT\"\n" + + " },\n" + + " \"value\":30,\n" + + " \"predicate\":{\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":0.0,\n" + + " \"dynamicValue\":{\n" + + " \"inherit\":false,\n" + + " \"sourceType\":\"CURRENT_DEVICE\",\n" + + " \"sourceAttribute\":\"tempThreshold\"\n" + + " }\n" + + " },\n" + + " \"operation\":\"EQUAL\"\n" + + " },\n" + + " \"valueType\":\"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"dashboardId\":null,\n" + + " \"alarmDetails\":null\n" + + " },\n" + + " \"CRITICAL\":{\n" + + " \"schedule\":null,\n" + + " \"condition\":{\n" + + " \"spec\":{\n" + + " \"type\":\"SIMPLE\"\n" + + " },\n" + + " \"condition\":[\n" + + " {\n" + + " \"key\":{\n" + + " \"key\":\"temperature\",\n" + + " \"type\":\"TIME_SERIES\"\n" + + " },\n" + + " \"value\":null,\n" + + " \"predicate\":{\n" + + " \"type\":\"NUMERIC\",\n" + + " \"value\":{\n" + + " \"userValue\":null,\n" + + " \"defaultValue\":50.0,\n" + + " \"dynamicValue\":null\n" + + " },\n" + + " \"operation\":\"GREATER\"\n" + + " },\n" + + " \"valueType\":\"NUMERIC\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"dashboardId\":null,\n" + + " \"alarmDetails\":null\n" + + " }\n" + + " },\n" + + " \"propagateRelationTypes\":null\n" + + " }\n" + + " ],\n" + + " \"configuration\":{\n" + + " \"type\":\"DEFAULT\"\n" + + " },\n" + + " \"provisionConfiguration\":{\n" + + " \"type\":\"ALLOW_CREATE_NEW_DEVICES\",\n" + + " \"provisionDeviceSecret\":\"vaxb9hzqdbz3oqukvomg\"\n" + + " },\n" + + " \"transportConfiguration\":{\n" + + " \"type\":\"MQTT\",\n" + + " \"deviceTelemetryTopic\":\"v1/devices/me/telemetry\",\n" + + " \"deviceAttributesTopic\":\"v1/devices/me/attributes\",\n" + + " \"transportPayloadTypeConfiguration\":{\n" + + " \"transportPayloadType\":\"PROTOBUF\",\n" + + " \"deviceTelemetryProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage telemetry;\\n\\nmessage SensorDataReading {\\n\\n optional double temperature = 1;\\n optional double humidity = 2;\\n InnerObject innerObject = 3;\\n\\n message InnerObject {\\n optional string key1 = 1;\\n optional bool key2 = 2;\\n optional double key3 = 3;\\n optional int32 key4 = 4;\\n optional string key5 = 5;\\n }\\n}\",\n" + + " \"deviceAttributesProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage attributes;\\n\\nmessage SensorConfiguration {\\n optional string firmwareVersion = 1;\\n optional string serialNumber = 2;\\n}\",\n" + + " \"deviceRpcRequestProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage rpc;\\n\\nmessage RpcRequestMsg {\\n optional string method = 1;\\n optional int32 requestId = 2;\\n optional string params = 3;\\n}\",\n" + + " \"deviceRpcResponseProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage rpc;\\n\\nmessage RpcResponseMsg {\\n optional string payload = 1;\\n}\"\n" + + " }\n" + + " }\n" + + "}" + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_DATA_DEFINITION = NEW_LINE + "# Device profile data definition" + NEW_LINE + + "Device profile data object contains alarm rules configuration, device provision strategy and transport type configuration for device connectivity. Let's review some examples. " + + "First one is the default device profile data configuration and second one - the custom one. " + + NEW_LINE + DEFAULT_DEVICE_PROFILE_DATA_EXAMPLE + NEW_LINE + CUSTOM_DEVICE_PROFILE_DATA_EXAMPLE + + NEW_LINE + "Let's review some specific objects examples related to the device profile configuration:"; + + protected static final String ALARM_SCHEDULE = NEW_LINE + "# Alarm Schedule" + NEW_LINE + + "Alarm Schedule JSON object represents the time interval during which the alarm rule is active. Note, " + + NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE + NEW_LINE + "means alarm rule is active all the time. " + + "**'daysOfWeek'** field represents Monday as 1, Tuesday as 2 and so on. **'startsOn'** and **'endsOn'** fields represent hours in millis (e.g. 64800000 = 18:00 or 6pm). " + + "**'enabled'** flag specifies if item in a custom rule is active for specific day of the week:" + NEW_LINE + + "## Specific Time Schedule" + NEW_LINE + + DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE + NEW_LINE + + "## Custom Schedule" + + NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE + NEW_LINE; + + protected static final String ALARM_CONDITION_TYPE = "# Alarm condition type (**'spec'**)" + NEW_LINE + + "Alarm condition type can be either simple, duration, or repeating. For example, 5 times in a row or during 5 minutes." + NEW_LINE + + "Note, **'userValue'** field is not used and reserved for future usage, **'dynamicValue'** is used for condition appliance by using the value of the **'sourceAttribute'** " + + "or else **'defaultValue'** is used (if **'sourceAttribute'** is absent).\n" + + "\n**'sourceType'** of the **'sourceAttribute'** can be: \n" + + " * 'CURRENT_DEVICE';\n" + + " * 'CURRENT_CUSTOMER';\n" + + " * 'CURRENT_TENANT'." + NEW_LINE + + "**'sourceAttribute'** can be inherited from the owner if **'inherit'** is set to true (for CURRENT_DEVICE and CURRENT_CUSTOMER)." + NEW_LINE + + "## Repeating alarm condition" + NEW_LINE + + DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE + NEW_LINE + + "## Duration alarm condition" + NEW_LINE + + DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE + NEW_LINE + + "**'unit'** can be: \n" + + " * 'SECONDS';\n" + + " * 'MINUTES';\n" + + " * 'HOURS';\n" + + " * 'DAYS'." + NEW_LINE; + + protected static final String PROVISION_CONFIGURATION = "# Provision Configuration" + NEW_LINE + + "There are 3 types of device provision configuration for the device profile: \n" + + " * 'DISABLED';\n" + + " * 'ALLOW_CREATE_NEW_DEVICES';\n" + + " * 'CHECK_PRE_PROVISIONED_DEVICES'." + NEW_LINE + + "Please refer to the [docs](https://thingsboard.io/docs/user-guide/device-provisioning/) for more details." + NEW_LINE; + + protected static final String DEVICE_PROFILE_DATA = DEVICE_PROFILE_DATA_DEFINITION + ALARM_SCHEDULE + ALARM_CONDITION_TYPE + + KEY_FILTERS_DESCRIPTION + PROVISION_CONFIGURATION + TRANSPORT_CONFIGURATION; + + protected static final String DEVICE_PROFILE_ID = "deviceProfileId"; + +} diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index d6d248a57c..12a5c74588 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -47,6 +47,20 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.List; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.HOME_DASHBOARD; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 11b5fa0727..6da5ce337c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; @@ -50,7 +51,6 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.model.SecurityUser; @@ -62,6 +62,27 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping("/api") 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 46262b6f30..e1caee9cc8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -86,6 +86,29 @@ import java.util.List; import java.util.UUID; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_NAME_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TYPE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.EdgeController.EDGE_ID; @RestController diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 9eb9ed4f84..6bba29ef9e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -49,460 +49,29 @@ import java.util.List; import java.util.Objects; import java.util.UUID; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_DATA; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TRANSPORT_TYPE_ALLOWABLE_VALUES; + @RestController @TbCoreComponent @RequestMapping("/api") @Slf4j public class DeviceProfileController extends BaseController { - private static final String COAP_TRANSPORT_CONFIGURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\":\"COAP\",\n" + - " \"clientSettings\":{\n" + - " \"edrxCycle\":null,\n" + - " \"powerMode\":\"DRX\",\n" + - " \"psmActivityTimer\":null,\n" + - " \"pagingTransmissionWindow\":null\n" + - " },\n" + - " \"coapDeviceTypeConfiguration\":{\n" + - " \"coapDeviceType\":\"DEFAULT\",\n" + - " \"transportPayloadTypeConfiguration\":{\n" + - " \"transportPayloadType\":\"JSON\"\n" + - " }\n" + - " }\n" + - "}" - + MARKDOWN_CODE_BLOCK_END; - - private static final String TRANSPORT_CONFIGURATION = "# Transport Configuration" + NEW_LINE + - "5 transport configuration types are available:\n" + - " * 'DEFAULT';\n" + - " * 'MQTT';\n" + - " * 'LWM2M';\n" + - " * 'COAP';\n" + - " * 'SNMP'." + NEW_LINE + "Default type supports basic MQTT, HTTP, CoAP and LwM2M transports. " + - "Please refer to the [docs](https://thingsboard.io/docs/user-guide/device-profiles/#transport-configuration) for more details about other types.\n" + - "\nSee another example of COAP transport configuration below:" + NEW_LINE + COAP_TRANSPORT_CONFIGURATION_EXAMPLE; - - private static final String ALARM_FILTER_KEY = "## Alarm Filter Key" + NEW_LINE + - "Filter Key defines either entity field, attribute, telemetry or constant. It is a JSON object that consists the key name and type. The following filter key types are supported:\n" + - " * 'ATTRIBUTE' - used for attributes values;\n" + - " * 'TIME_SERIES' - used for time-series values;\n" + - " * 'ENTITY_FIELD' - used for accessing entity fields like 'name', 'label', etc. The list of available fields depends on the entity type;\n" + - " * 'CONSTANT' - constant value specified." + NEW_LINE + "Let's review the example:" + NEW_LINE + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"TIME_SERIES\",\n" + - " \"key\": \"temperature\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END; - - private static final String FILTER_PREDICATE = NEW_LINE + "## Filter Predicate" + NEW_LINE + - "Filter Predicate defines the logical expression to evaluate. The list of available operations depends on the filter value type, see above. " + - "Platform supports 4 predicate types: 'STRING', 'NUMERIC', 'BOOLEAN' and 'COMPLEX'. The last one allows to combine multiple operations over one filter key." + NEW_LINE + - "Simple predicate example to check 'value < 100': " + NEW_LINE + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"operation\": \"LESS\",\n" + - " \"value\": {\n" + - " \"userValue\": null,\n" + - " \"defaultValue\": 100,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + NEW_LINE + - "Complex predicate example, to check 'value < 10 or value > 20': " + NEW_LINE + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"COMPLEX\",\n" + - " \"operation\": \"OR\",\n" + - " \"predicates\": [\n" + - " {\n" + - " \"operation\": \"LESS\",\n" + - " \"value\": {\n" + - " \"userValue\": null,\n" + - " \"defaultValue\": 10,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " },\n" + - " {\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"userValue\": null,\n" + - " \"defaultValue\": 20,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " }\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + NEW_LINE + - "More complex predicate example, to check 'value < 10 or (value > 50 && value < 60)': " + NEW_LINE + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"COMPLEX\",\n" + - " \"operation\": \"OR\",\n" + - " \"predicates\": [\n" + - " {\n" + - " \"operation\": \"LESS\",\n" + - " \"value\": {\n" + - " \"userValue\": null,\n" + - " \"defaultValue\": 10,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " },\n" + - " {\n" + - " \"type\": \"COMPLEX\",\n" + - " \"operation\": \"AND\",\n" + - " \"predicates\": [\n" + - " {\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"userValue\": null,\n" + - " \"defaultValue\": 50,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " },\n" + - " {\n" + - " \"operation\": \"LESS\",\n" + - " \"value\": {\n" + - " \"userValue\": null,\n" + - " \"defaultValue\": 60,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " }\n" + - " ]\n" + - " }\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + NEW_LINE + - "You may also want to replace hardcoded values (for example, temperature > 20) with the more dynamic " + - "expression (for example, temperature > value of the tenant attribute with key 'temperatureThreshold'). " + - "It is possible to use 'dynamicValue' to define attribute of the tenant, customer or device. " + - "See example below:" + NEW_LINE + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"userValue\": null,\n" + - " \"defaultValue\": 0,\n" + - " \"dynamicValue\": {\n" + - " \"inherit\": false,\n" + - " \"sourceType\": \"CURRENT_TENANT\",\n" + - " \"sourceAttribute\": \"temperatureThreshold\"\n" + - " }\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + NEW_LINE + - "Note that you may use 'CURRENT_DEVICE', 'CURRENT_CUSTOMER' and 'CURRENT_TENANT' as a 'sourceType'. The 'defaultValue' is used when the attribute with such a name is not defined for the chosen source. " + - "The 'sourceAttribute' can be inherited from the owner of the specified 'sourceType' if 'inherit' is set to true."; - - private static final String KEY_FILTERS_DESCRIPTION = "# Key Filters" + NEW_LINE + - "Key filter objects are created under the **'condition'** array. They allow you to define complex logical expressions over entity field, " + - "attribute, latest time-series value or constant. The filter is defined using 'key', 'valueType', " + - "'value' (refers to the value of the 'CONSTANT' alarm filter key type) and 'predicate' objects. Let's review each object:" + NEW_LINE + - ALARM_FILTER_KEY + FILTER_VALUE_TYPE + NEW_LINE + FILTER_PREDICATE + NEW_LINE; - - private static final String DEFAULT_DEVICE_PROFILE_DATA_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + - " \"alarms\":[\n" + - " ],\n" + - " \"configuration\":{\n" + - " \"type\":\"DEFAULT\"\n" + - " },\n" + - " \"provisionConfiguration\":{\n" + - " \"type\":\"DISABLED\",\n" + - " \"provisionDeviceSecret\":null\n" + - " },\n" + - " \"transportConfiguration\":{\n" + - " \"type\":\"DEFAULT\"\n" + - " }\n" + - "}" + MARKDOWN_CODE_BLOCK_END; - - private static final String CUSTOM_DEVICE_PROFILE_DATA_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + - " \"alarms\":[\n" + - " {\n" + - " \"id\":\"2492b935-1226-59e9-8615-17d8978a4f93\",\n" + - " \"alarmType\":\"Temperature Alarm\",\n" + - " \"clearRule\":{\n" + - " \"schedule\":null,\n" + - " \"condition\":{\n" + - " \"spec\":{\n" + - " \"type\":\"SIMPLE\"\n" + - " },\n" + - " \"condition\":[\n" + - " {\n" + - " \"key\":{\n" + - " \"key\":\"temperature\",\n" + - " \"type\":\"TIME_SERIES\"\n" + - " },\n" + - " \"value\":null,\n" + - " \"predicate\":{\n" + - " \"type\":\"NUMERIC\",\n" + - " \"value\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":30.0,\n" + - " \"dynamicValue\":null\n" + - " },\n" + - " \"operation\":\"LESS\"\n" + - " },\n" + - " \"valueType\":\"NUMERIC\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " \"dashboardId\":null,\n" + - " \"alarmDetails\":null\n" + - " },\n" + - " \"propagate\":false,\n" + - " \"createRules\":{\n" + - " \"MAJOR\":{\n" + - " \"schedule\":{\n" + - " \"type\":\"SPECIFIC_TIME\",\n" + - " \"endsOn\":64800000,\n" + - " \"startsOn\":43200000,\n" + - " \"timezone\":\"Europe/Kiev\",\n" + - " \"daysOfWeek\":[\n" + - " 1,\n" + - " 3,\n" + - " 5\n" + - " ]\n" + - " },\n" + - " \"condition\":{\n" + - " \"spec\":{\n" + - " \"type\":\"DURATION\",\n" + - " \"unit\":\"MINUTES\",\n" + - " \"predicate\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":30,\n" + - " \"dynamicValue\":null\n" + - " }\n" + - " },\n" + - " \"condition\":[\n" + - " {\n" + - " \"key\":{\n" + - " \"key\":\"temperature\",\n" + - " \"type\":\"TIME_SERIES\"\n" + - " },\n" + - " \"value\":null,\n" + - " \"predicate\":{\n" + - " \"type\":\"COMPLEX\",\n" + - " \"operation\":\"OR\",\n" + - " \"predicates\":[\n" + - " {\n" + - " \"type\":\"NUMERIC\",\n" + - " \"value\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":50.0,\n" + - " \"dynamicValue\":null\n" + - " },\n" + - " \"operation\":\"LESS_OR_EQUAL\"\n" + - " },\n" + - " {\n" + - " \"type\":\"NUMERIC\",\n" + - " \"value\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":30.0,\n" + - " \"dynamicValue\":null\n" + - " },\n" + - " \"operation\":\"GREATER\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " \"valueType\":\"NUMERIC\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " \"dashboardId\":null,\n" + - " \"alarmDetails\":null\n" + - " },\n" + - " \"WARNING\":{\n" + - " \"schedule\":{\n" + - " \"type\":\"CUSTOM\",\n" + - " \"items\":[\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":1\n" + - " },\n" + - " {\n" + - " \"endsOn\":64800000,\n" + - " \"enabled\":true,\n" + - " \"startsOn\":43200000,\n" + - " \"dayOfWeek\":2\n" + - " },\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":3\n" + - " },\n" + - " {\n" + - " \"endsOn\":57600000,\n" + - " \"enabled\":true,\n" + - " \"startsOn\":36000000,\n" + - " \"dayOfWeek\":4\n" + - " },\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":5\n" + - " },\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":6\n" + - " },\n" + - " {\n" + - " \"endsOn\":0,\n" + - " \"enabled\":false,\n" + - " \"startsOn\":0,\n" + - " \"dayOfWeek\":7\n" + - " }\n" + - " ],\n" + - " \"timezone\":\"Europe/Kiev\"\n" + - " },\n" + - " \"condition\":{\n" + - " \"spec\":{\n" + - " \"type\":\"REPEATING\",\n" + - " \"predicate\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":5,\n" + - " \"dynamicValue\":null\n" + - " }\n" + - " },\n" + - " \"condition\":[\n" + - " {\n" + - " \"key\":{\n" + - " \"key\":\"tempConstant\",\n" + - " \"type\":\"CONSTANT\"\n" + - " },\n" + - " \"value\":30,\n" + - " \"predicate\":{\n" + - " \"type\":\"NUMERIC\",\n" + - " \"value\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":0.0,\n" + - " \"dynamicValue\":{\n" + - " \"inherit\":false,\n" + - " \"sourceType\":\"CURRENT_DEVICE\",\n" + - " \"sourceAttribute\":\"tempThreshold\"\n" + - " }\n" + - " },\n" + - " \"operation\":\"EQUAL\"\n" + - " },\n" + - " \"valueType\":\"NUMERIC\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " \"dashboardId\":null,\n" + - " \"alarmDetails\":null\n" + - " },\n" + - " \"CRITICAL\":{\n" + - " \"schedule\":null,\n" + - " \"condition\":{\n" + - " \"spec\":{\n" + - " \"type\":\"SIMPLE\"\n" + - " },\n" + - " \"condition\":[\n" + - " {\n" + - " \"key\":{\n" + - " \"key\":\"temperature\",\n" + - " \"type\":\"TIME_SERIES\"\n" + - " },\n" + - " \"value\":null,\n" + - " \"predicate\":{\n" + - " \"type\":\"NUMERIC\",\n" + - " \"value\":{\n" + - " \"userValue\":null,\n" + - " \"defaultValue\":50.0,\n" + - " \"dynamicValue\":null\n" + - " },\n" + - " \"operation\":\"GREATER\"\n" + - " },\n" + - " \"valueType\":\"NUMERIC\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " \"dashboardId\":null,\n" + - " \"alarmDetails\":null\n" + - " }\n" + - " },\n" + - " \"propagateRelationTypes\":null\n" + - " }\n" + - " ],\n" + - " \"configuration\":{\n" + - " \"type\":\"DEFAULT\"\n" + - " },\n" + - " \"provisionConfiguration\":{\n" + - " \"type\":\"ALLOW_CREATE_NEW_DEVICES\",\n" + - " \"provisionDeviceSecret\":\"vaxb9hzqdbz3oqukvomg\"\n" + - " },\n" + - " \"transportConfiguration\":{\n" + - " \"type\":\"MQTT\",\n" + - " \"deviceTelemetryTopic\":\"v1/devices/me/telemetry\",\n" + - " \"deviceAttributesTopic\":\"v1/devices/me/attributes\",\n" + - " \"transportPayloadTypeConfiguration\":{\n" + - " \"transportPayloadType\":\"PROTOBUF\",\n" + - " \"deviceTelemetryProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage telemetry;\\n\\nmessage SensorDataReading {\\n\\n optional double temperature = 1;\\n optional double humidity = 2;\\n InnerObject innerObject = 3;\\n\\n message InnerObject {\\n optional string key1 = 1;\\n optional bool key2 = 2;\\n optional double key3 = 3;\\n optional int32 key4 = 4;\\n optional string key5 = 5;\\n }\\n}\",\n" + - " \"deviceAttributesProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage attributes;\\n\\nmessage SensorConfiguration {\\n optional string firmwareVersion = 1;\\n optional string serialNumber = 2;\\n}\",\n" + - " \"deviceRpcRequestProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage rpc;\\n\\nmessage RpcRequestMsg {\\n optional string method = 1;\\n optional int32 requestId = 2;\\n optional string params = 3;\\n}\",\n" + - " \"deviceRpcResponseProtoSchema\":\"syntax =\\\"proto3\\\";\\npackage rpc;\\n\\nmessage RpcResponseMsg {\\n optional string payload = 1;\\n}\"\n" + - " }\n" + - " }\n" + - "}" + MARKDOWN_CODE_BLOCK_END; - private static final String DEVICE_PROFILE_DATA_DEFINITION = NEW_LINE + "# Device profile data definition" + NEW_LINE + - "Device profile data object contains alarm rules configuration, device provision strategy and transport type configuration for device connectivity. Let's review some examples. " + - "First one is the default device profile data configuration and second one - the custom one. " + - NEW_LINE + DEFAULT_DEVICE_PROFILE_DATA_EXAMPLE + NEW_LINE + CUSTOM_DEVICE_PROFILE_DATA_EXAMPLE + - NEW_LINE + "Let's review some specific objects examples related to the device profile configuration:"; - - private static final String ALARM_SCHEDULE = NEW_LINE + "# Alarm Schedule" + NEW_LINE + - "Alarm Schedule JSON object represents the time interval during which the alarm rule is active. Note, " + - NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE + NEW_LINE + "means alarm rule is active all the time. " + - "**'daysOfWeek'** field represents Monday as 1, Tuesday as 2 and so on. **'startsOn'** and **'endsOn'** fields represent hours in millis (e.g. 64800000 = 18:00 or 6pm). " + - "**'enabled'** flag specifies if item in a custom rule is active for specific day of the week:" + NEW_LINE + - "## Specific Time Schedule" + NEW_LINE + - DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE + NEW_LINE + - "## Custom Schedule" + - NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE + NEW_LINE; - - private static final String ALARM_CONDITION_TYPE = "# Alarm condition type (**'spec'**)" + NEW_LINE + - "Alarm condition type can be either simple, duration, or repeating. For example, 5 times in a row or during 5 minutes." + NEW_LINE + - "Note, **'userValue'** field is not used and reserved for future usage, **'dynamicValue'** is used for condition appliance by using the value of the **'sourceAttribute'** " + - "or else **'defaultValue'** is used (if **'sourceAttribute'** is absent).\n" + - "\n**'sourceType'** of the **'sourceAttribute'** can be: \n" + - " * 'CURRENT_DEVICE';\n" + - " * 'CURRENT_CUSTOMER';\n" + - " * 'CURRENT_TENANT'." + NEW_LINE + - "**'sourceAttribute'** can be inherited from the owner if **'inherit'** is set to true (for CURRENT_DEVICE and CURRENT_CUSTOMER)." + NEW_LINE + - "## Repeating alarm condition" + NEW_LINE + - DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE + NEW_LINE + - "## Duration alarm condition" + NEW_LINE + - DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE + NEW_LINE + - "**'unit'** can be: \n" + - " * 'SECONDS';\n" + - " * 'MINUTES';\n" + - " * 'HOURS';\n" + - " * 'DAYS'." + NEW_LINE; - - private static final String PROVISION_CONFIGURATION = "# Provision Configuration" + NEW_LINE + - "There are 3 types of device provision configuration for the device profile: \n" + - " * 'DISABLED';\n" + - " * 'ALLOW_CREATE_NEW_DEVICES';\n" + - " * 'CHECK_PRE_PROVISIONED_DEVICES'." + NEW_LINE + - "Please refer to the [docs](https://thingsboard.io/docs/user-guide/device-provisioning/) for more details." + NEW_LINE; - - private static final String DEVICE_PROFILE_DATA = DEVICE_PROFILE_DATA_DEFINITION + ALARM_SCHEDULE + ALARM_CONDITION_TYPE + - KEY_FILTERS_DESCRIPTION + PROVISION_CONFIGURATION + TRANSPORT_CONFIGURATION; - - private static final String DEVICE_PROFILE_ID = "deviceProfileId"; @Autowired private TimeseriesService timeseriesService; diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index d518c6e201..219041e82c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -69,6 +69,22 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_TYPE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @Slf4j diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java index e688ab1375..72fbba0fe6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java @@ -37,6 +37,15 @@ import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; + @Slf4j @RestController @TbCoreComponent diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 46bf285178..019066c636 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -39,634 +39,15 @@ import org.thingsboard.server.common.data.query.EntityDataQuery; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.query.EntityQueryService; +import static org.thingsboard.server.controller.ControllerConstants.ALARM_DATA_QUERY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_COUNT_QUERY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_DATA_QUERY_DESCRIPTION; + @RestController @TbCoreComponent @RequestMapping("/api") public class EntityQueryController extends BaseController { - private static final String SINGLE_ENTITY = "\n\n## Single Entity\n\n" + - "Allows to filter only one entity based on the id. For example, this entity filter selects certain device:\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"singleEntity\",\n" + - " \"singleEntity\": {\n" + - " \"id\": \"d521edb0-2a7a-11ec-94eb-213c95f54092\",\n" + - " \"entityType\": \"DEVICE\"\n" + - " }\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String ENTITY_LIST = "\n\n## Entity List Filter\n\n" + - "Allows to filter entities of the same type using their ids. For example, this entity filter selects two devices:\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"entityList\",\n" + - " \"entityType\": \"DEVICE\",\n" + - " \"entityList\": [\n" + - " \"e6501f30-2a7a-11ec-94eb-213c95f54092\",\n" + - " \"e6657bf0-2a7a-11ec-94eb-213c95f54092\"\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String ENTITY_NAME = "\n\n## Entity Name Filter\n\n" + - "Allows to filter entities of the same type using the **'starts with'** expression over entity name. " + - "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"entityName\",\n" + - " \"entityType\": \"DEVICE\",\n" + - " \"entityNameFilter\": \"Air Quality\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String ENTITY_TYPE = "\n\n## Entity Type Filter\n\n" + - "Allows to filter entities based on their type (CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, etc)" + - "For example, this entity filter selects all tenant customers:\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"entityType\",\n" + - " \"entityType\": \"CUSTOMER\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String ASSET_TYPE = "\n\n## Asset Type Filter\n\n" + - "Allows to filter assets based on their type and the **'starts with'** expression over their name. " + - "For example, this entity filter selects all 'charging station' assets which name starts with 'Tesla':\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"assetType\",\n" + - " \"assetType\": \"charging station\",\n" + - " \"assetNameFilter\": \"Tesla\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String DEVICE_TYPE = "\n\n## Device Type Filter\n\n" + - "Allows to filter devices based on their type and the **'starts with'** expression over their name. " + - "For example, this entity filter selects all 'Temperature Sensor' devices which name starts with 'ABC':\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"deviceType\",\n" + - " \"deviceType\": \"Temperature Sensor\",\n" + - " \"deviceNameFilter\": \"ABC\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String EDGE_TYPE = "\n\n## Edge Type Filter\n\n" + - "Allows to filter edge instances based on their type and the **'starts with'** expression over their name. " + - "For example, this entity filter selects all 'Factory' edge instances which name starts with 'Nevada':\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"edgeType\",\n" + - " \"edgeType\": \"Factory\",\n" + - " \"edgeNameFilter\": \"Nevada\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String ENTITY_VIEW_TYPE = "\n\n## Entity View Filter\n\n" + - "Allows to filter entity views based on their type and the **'starts with'** expression over their name. " + - "For example, this entity filter selects all 'Concrete Mixer' entity views which name starts with 'CAT':\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"entityViewType\",\n" + - " \"entityViewType\": \"Concrete Mixer\",\n" + - " \"entityViewNameFilter\": \"CAT\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String API_USAGE = "\n\n## Api Usage Filter\n\n" + - "Allows to query for Api Usage based on optional customer id. If the customer id is not set, returns current tenant API usage." + - "For example, this entity filter selects the 'Api Usage' entity for customer with id 'e6501f30-2a7a-11ec-94eb-213c95f54092':\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"apiUsageState\",\n" + - " \"customerId\": {\n" + - " \"id\": \"d521edb0-2a7a-11ec-94eb-213c95f54092\",\n" + - " \"entityType\": \"CUSTOMER\"\n" + - " }\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String MAX_LEVEL_DESCRIPTION = "Possible direction values are 'TO' and 'FROM'. The 'maxLevel' defines how many relation levels should the query search 'recursively'. "; - private static final String FETCH_LAST_LEVEL_ONLY_DESCRIPTION = "Assuming the 'maxLevel' is > 1, the 'fetchLastLevelOnly' defines either to return all related entities or only entities that are on the last level of relations. "; - - private static final String RELATIONS_QUERY_FILTER = "\n\n## Relations Query Filter\n\n" + - "Allows to filter entities that are related to the provided root entity. " + - MAX_LEVEL_DESCRIPTION + - FETCH_LAST_LEVEL_ONLY_DESCRIPTION + - "The 'filter' object allows you to define the relation type and set of acceptable entity types to search for. " + - "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only those who match the 'filters'.\n\n" + - "For example, this entity filter selects all devices and assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092':\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"relationsQuery\",\n" + - " \"rootEntity\": {\n" + - " \"entityType\": \"ASSET\",\n" + - " \"id\": \"e51de0c0-2a7a-11ec-94eb-213c95f54092\"\n" + - " },\n" + - " \"direction\": \"FROM\",\n" + - " \"maxLevel\": 1,\n" + - " \"fetchLastLevelOnly\": false,\n" + - " \"filters\": [\n" + - " {\n" + - " \"relationType\": \"Contains\",\n" + - " \"entityTypes\": [\n" + - " \"DEVICE\",\n" + - " \"ASSET\"\n" + - " ]\n" + - " }\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - - private static final String ASSET_QUERY_FILTER = "\n\n## Asset Search Query\n\n" + - "Allows to filter assets that are related to the provided root entity. Filters related assets based on the relation type and set of asset types. " + - MAX_LEVEL_DESCRIPTION + - FETCH_LAST_LEVEL_ONLY_DESCRIPTION + - "The 'relationType' defines the type of the relation to search for. " + - "The 'assetTypes' defines the type of the asset to search for. " + - "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only assets that match 'relationType' and 'assetTypes' conditions.\n\n" + - "For example, this entity filter selects 'charging station' assets which are related to the asset with id 'e51de0c0-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"assetSearchQuery\",\n" + - " \"rootEntity\": {\n" + - " \"entityType\": \"ASSET\",\n" + - " \"id\": \"e51de0c0-2a7a-11ec-94eb-213c95f54092\"\n" + - " },\n" + - " \"direction\": \"FROM\",\n" + - " \"maxLevel\": 1,\n" + - " \"fetchLastLevelOnly\": false,\n" + - " \"relationType\": \"Contains\",\n" + - " \"assetTypes\": [\n" + - " \"charging station\"\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String DEVICE_QUERY_FILTER = "\n\n## Device Search Query\n\n" + - "Allows to filter devices that are related to the provided root entity. Filters related devices based on the relation type and set of device types. " + - MAX_LEVEL_DESCRIPTION + - FETCH_LAST_LEVEL_ONLY_DESCRIPTION + - "The 'relationType' defines the type of the relation to search for. " + - "The 'deviceTypes' defines the type of the device to search for. " + - "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + - "For example, this entity filter selects 'Charging port' and 'Air Quality Sensor' devices which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"deviceSearchQuery\",\n" + - " \"rootEntity\": {\n" + - " \"entityType\": \"ASSET\",\n" + - " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + - " },\n" + - " \"direction\": \"FROM\",\n" + - " \"maxLevel\": 2,\n" + - " \"fetchLastLevelOnly\": true,\n" + - " \"relationType\": \"Contains\",\n" + - " \"deviceTypes\": [\n" + - " \"Air Quality Sensor\",\n" + - " \"Charging port\"\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String EV_QUERY_FILTER = "\n\n## Entity View Query\n\n" + - "Allows to filter entity views that are related to the provided root entity. Filters related entity views based on the relation type and set of entity view types. " + - MAX_LEVEL_DESCRIPTION + - FETCH_LAST_LEVEL_ONLY_DESCRIPTION + - "The 'relationType' defines the type of the relation to search for. " + - "The 'entityViewTypes' defines the type of the entity view to search for. " + - "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + - "For example, this entity filter selects 'Concrete mixer' entity views which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"entityViewSearchQuery\",\n" + - " \"rootEntity\": {\n" + - " \"entityType\": \"ASSET\",\n" + - " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + - " },\n" + - " \"direction\": \"FROM\",\n" + - " \"maxLevel\": 1,\n" + - " \"fetchLastLevelOnly\": false,\n" + - " \"relationType\": \"Contains\",\n" + - " \"entityViewTypes\": [\n" + - " \"Concrete mixer\"\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String EDGE_QUERY_FILTER = "\n\n## Edge Search Query\n\n" + - "Allows to filter edge instances that are related to the provided root entity. Filters related edge instances based on the relation type and set of edge types. " + - MAX_LEVEL_DESCRIPTION + - FETCH_LAST_LEVEL_ONLY_DESCRIPTION + - "The 'relationType' defines the type of the relation to search for. " + - "The 'deviceTypes' defines the type of the device to search for. " + - "The relation query calculates all related entities, even if they are filtered using different relation types, and then extracts only devices that match 'relationType' and 'deviceTypes' conditions.\n\n" + - "For example, this entity filter selects 'Factory' edge instances which are related to the asset with id 'e52b0020-2a7a-11ec-94eb-213c95f54092' using 'Contains' relation:\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"deviceSearchQuery\",\n" + - " \"rootEntity\": {\n" + - " \"entityType\": \"ASSET\",\n" + - " \"id\": \"e52b0020-2a7a-11ec-94eb-213c95f54092\"\n" + - " },\n" + - " \"direction\": \"FROM\",\n" + - " \"maxLevel\": 2,\n" + - " \"fetchLastLevelOnly\": true,\n" + - " \"relationType\": \"Contains\",\n" + - " \"edgeTypes\": [\n" + - " \"Factory\"\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String EMPTY = "\n\n## Entity Type Filter\n\n" + - "Allows to filter multiple entities of the same type using the **'starts with'** expression over entity name. " + - "For example, this entity filter selects all devices which name starts with 'Air Quality':\n\n" + - MARKDOWN_CODE_BLOCK_START + - "" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String ENTITY_FILTERS = - "\n\n # Entity Filters" + - "\nEntity Filter body depends on the 'type' parameter. Let's review available entity filter types. In fact, they do correspond to available dashboard aliases." + - SINGLE_ENTITY + ENTITY_LIST + ENTITY_NAME + ENTITY_TYPE + ASSET_TYPE + DEVICE_TYPE + EDGE_TYPE + ENTITY_VIEW_TYPE + API_USAGE + RELATIONS_QUERY_FILTER - + ASSET_QUERY_FILTER + DEVICE_QUERY_FILTER + EV_QUERY_FILTER + EDGE_QUERY_FILTER; - - private static final String FILTER_KEY = "\n\n## Filter Key\n\n" + - "Filter Key defines either entity field, attribute or telemetry. It is a JSON object that consists the key name and type. " + - "The following filter key types are supported: \n\n" + - " * 'CLIENT_ATTRIBUTE' - used for client attributes; \n" + - " * 'SHARED_ATTRIBUTE' - used for shared attributes; \n" + - " * 'SERVER_ATTRIBUTE' - used for server attributes; \n" + - " * 'ATTRIBUTE' - used for any of the above; \n" + - " * 'TIME_SERIES' - used for time-series values; \n" + - " * 'ENTITY_FIELD' - used for accessing entity fields like 'name', 'label', etc. The list of available fields depends on the entity type; \n" + - " * 'ALARM_FIELD' - similar to entity field, but is used in alarm queries only; \n" + - "\n\n Let's review the example:\n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"TIME_SERIES\",\n" + - " \"key\": \"temperature\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - - private static final String FILTER_PREDICATE = "\n\n## Filter Predicate\n\n" + - "Filter Predicate defines the logical expression to evaluate. The list of available operations depends on the filter value type, see above. " + - "Platform supports 4 predicate types: 'STRING', 'NUMERIC', 'BOOLEAN' and 'COMPLEX'. The last one allows to combine multiple operations over one filter key." + - "\n\nSimple predicate example to check 'value < 100': \n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"operation\": \"LESS\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 100,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - "\n\nComplex predicate example, to check 'value < 10 or value > 20': \n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"COMPLEX\",\n" + - " \"operation\": \"OR\",\n" + - " \"predicates\": [\n" + - " {\n" + - " \"operation\": \"LESS\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 10,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " },\n" + - " {\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 20,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " }\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - "\n\nMore complex predicate example, to check 'value < 10 or (value > 50 && value < 60)': \n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"type\": \"COMPLEX\",\n" + - " \"operation\": \"OR\",\n" + - " \"predicates\": [\n" + - " {\n" + - " \"operation\": \"LESS\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 10,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " },\n" + - " {\n" + - " \"type\": \"COMPLEX\",\n" + - " \"operation\": \"AND\",\n" + - " \"predicates\": [\n" + - " {\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 50,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " },\n" + - " {\n" + - " \"operation\": \"LESS\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 60,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " }\n" + - " ]\n" + - " }\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - "\n\n You may also want to replace hardcoded values (for example, temperature > 20) with the more dynamic " + - "expression (for example, temperature > 'value of the tenant attribute with key 'temperatureThreshold'). " + - "It is possible to use 'dynamicValue' to define attribute of the tenant, customer or user that is performing the API call. " + - "See example below: \n\n" + - MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 0,\n" + - " \"dynamicValue\": {\n" + - " \"sourceType\": \"CURRENT_USER\",\n" + - " \"sourceAttribute\": \"temperatureThreshold\"\n" + - " }\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - "\n\n Note that you may use 'CURRENT_USER', 'CURRENT_CUSTOMER' and 'CURRENT_TENANT' as a 'sourceType'. The 'defaultValue' is used when the attribute with such a name is not defined for the chosen source."; - - private static final String KEY_FILTERS = - "\n\n # Key Filters" + - "\nKey Filter allows you to define complex logical expressions over entity field, attribute or latest time-series value. The filter is defined using 'key', 'valueType' and 'predicate' objects. " + - "Single Entity Query may have zero, one or multiple predicates. If multiple filters are defined, they are evaluated using logical 'AND'. " + - "The example below checks that temperature of the entity is above 20 degrees:" + - "\n\n" + MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"key\": {\n" + - " \"type\": \"TIME_SERIES\",\n" + - " \"key\": \"temperature\"\n" + - " },\n" + - " \"valueType\": \"NUMERIC\",\n" + - " \"predicate\": {\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 20,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " }\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - "\n\n Now let's review 'key', 'valueType' and 'predicate' objects in detail." - + FILTER_KEY + FILTER_VALUE_TYPE + FILTER_PREDICATE; - - private static final String ENTITY_COUNT_QUERY_DESCRIPTION = - "Allows to run complex queries to search the count of platform entities (devices, assets, customers, etc) " + - "based on the combination of main entity filter and multiple key filters. Returns the number of entities that match the query definition.\n\n" + - "# Query Definition\n\n" + - "\n\nMain **entity filter** is mandatory and defines generic search criteria. " + - "For example, \"find all devices with profile 'Moisture Sensor'\" or \"Find all devices related to asset 'Building A'\"" + - "\n\nOptional **key filters** allow to filter results of the entity filter by complex criteria against " + - "main entity fields (name, label, type, etc), attributes and telemetry. " + - "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"." + - "\n\nLet's review the example:" + - "\n\n" + MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"entityFilter\": {\n" + - " \"type\": \"entityType\",\n" + - " \"entityType\": \"DEVICE\"\n" + - " },\n" + - " \"keyFilters\": [\n" + - " {\n" + - " \"key\": {\n" + - " \"type\": \"ATTRIBUTE\",\n" + - " \"key\": \"active\"\n" + - " },\n" + - " \"valueType\": \"BOOLEAN\",\n" + - " \"predicate\": {\n" + - " \"operation\": \"EQUAL\",\n" + - " \"value\": {\n" + - " \"defaultValue\": true,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"BOOLEAN\"\n" + - " }\n" + - " }\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + - ENTITY_FILTERS + - KEY_FILTERS + - TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; - - private static final String ENTITY_DATA_QUERY_DESCRIPTION = - "Allows to run complex queries over platform entities (devices, assets, customers, etc) " + - "based on the combination of main entity filter and multiple key filters. " + - "Returns the paginated result of the query that contains requested entity fields and latest values of requested attributes and time-series data.\n\n" + - "# Query Definition\n\n" + - "\n\nMain **entity filter** is mandatory and defines generic search criteria. " + - "For example, \"find all devices with profile 'Moisture Sensor'\" or \"Find all devices related to asset 'Building A'\"" + - "\n\nOptional **key filters** allow to filter results of the **entity filter** by complex criteria against " + - "main entity fields (name, label, type, etc), attributes and telemetry. " + - "For example, \"temperature > 20 or temperature< 10\" or \"name starts with 'T', and attribute 'model' is 'T1000', and timeseries field 'batteryLevel' > 40\"." + - "\n\nThe **entity fields** and **latest values** contains list of entity fields and latest attribute/telemetry fields to fetch for each entity." + - "\n\nThe **page link** contains information about the page to fetch and the sort ordering." + - "\n\nLet's review the example:" + - "\n\n" + MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"entityFilter\": {\n" + - " \"type\": \"entityType\",\n" + - " \"resolveMultiple\": true,\n" + - " \"entityType\": \"DEVICE\"\n" + - " },\n" + - " \"keyFilters\": [\n" + - " {\n" + - " \"key\": {\n" + - " \"type\": \"TIME_SERIES\",\n" + - " \"key\": \"temperature\"\n" + - " },\n" + - " \"valueType\": \"NUMERIC\",\n" + - " \"predicate\": {\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 0,\n" + - " \"dynamicValue\": {\n" + - " \"sourceType\": \"CURRENT_USER\",\n" + - " \"sourceAttribute\": \"temperatureThreshold\",\n" + - " \"inherit\": false\n" + - " }\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " }\n" + - " }\n" + - " ],\n" + - " \"entityFields\": [\n" + - " {\n" + - " \"type\": \"ENTITY_FIELD\",\n" + - " \"key\": \"name\"\n" + - " },\n" + - " {\n" + - " \"type\": \"ENTITY_FIELD\",\n" + - " \"key\": \"label\"\n" + - " },\n" + - " {\n" + - " \"type\": \"ENTITY_FIELD\",\n" + - " \"key\": \"additionalInfo\"\n" + - " }\n" + - " ],\n" + - " \"latestValues\": [\n" + - " {\n" + - " \"type\": \"ATTRIBUTE\",\n" + - " \"key\": \"model\"\n" + - " },\n" + - " {\n" + - " \"type\": \"TIME_SERIES\",\n" + - " \"key\": \"temperature\"\n" + - " }\n" + - " ],\n" + - " \"pageLink\": {\n" + - " \"page\": 0,\n" + - " \"pageSize\": 10,\n" + - " \"sortOrder\": {\n" + - " \"key\": {\n" + - " \"key\": \"name\",\n" + - " \"type\": \"ENTITY_FIELD\"\n" + - " },\n" + - " \"direction\": \"ASC\"\n" + - " }\n" + - " }\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + - ENTITY_FILTERS + - KEY_FILTERS + - TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; - - - private static final String ALARM_DATA_QUERY_DESCRIPTION = "This method description defines how Alarm Data Query extends the Entity Data Query. " + - "See method 'Find Entity Data by Query' first to get the info about 'Entity Data Query'." + - "\n\n The platform will first search the entities that match the entity and key filters. Then, the platform will use 'Alarm Page Link' to filter the alarms related to those entities. " + - "Finally, platform fetch the properties of alarm that are defined in the **'alarmFields'** and combine them with the other entity, attribute and latest time-series fields to return the result. " + - "\n\n See example of the alarm query below. The query will search first 100 active alarms with type 'Temperature Alarm' or 'Fire Alarm' for any device with current temperature > 0. " + - "The query will return combination of the entity fields: name of the device, device model and latest temperature reading and alarms fields: createdTime, type, severity and status: " + - "\n\n" + MARKDOWN_CODE_BLOCK_START + - "{\n" + - " \"entityFilter\": {\n" + - " \"type\": \"entityType\",\n" + - " \"resolveMultiple\": true,\n" + - " \"entityType\": \"DEVICE\"\n" + - " },\n" + - " \"pageLink\": {\n" + - " \"page\": 0,\n" + - " \"pageSize\": 100,\n" + - " \"textSearch\": null,\n" + - " \"searchPropagatedAlarms\": false,\n" + - " \"statusList\": [\n" + - " \"ACTIVE\"\n" + - " ],\n" + - " \"severityList\": [\n" + - " \"CRITICAL\",\n" + - " \"MAJOR\"\n" + - " ],\n" + - " \"typeList\": [\n" + - " \"Temperature Alarm\",\n" + - " \"Fire Alarm\"\n" + - " ],\n" + - " \"sortOrder\": {\n" + - " \"key\": {\n" + - " \"key\": \"createdTime\",\n" + - " \"type\": \"ALARM_FIELD\"\n" + - " },\n" + - " \"direction\": \"DESC\"\n" + - " },\n" + - " \"timeWindow\": 86400000\n" + - " },\n" + - " \"keyFilters\": [\n" + - " {\n" + - " \"key\": {\n" + - " \"type\": \"TIME_SERIES\",\n" + - " \"key\": \"temperature\"\n" + - " },\n" + - " \"valueType\": \"NUMERIC\",\n" + - " \"predicate\": {\n" + - " \"operation\": \"GREATER\",\n" + - " \"value\": {\n" + - " \"defaultValue\": 0,\n" + - " \"dynamicValue\": null\n" + - " },\n" + - " \"type\": \"NUMERIC\"\n" + - " }\n" + - " }\n" + - " ],\n" + - " \"alarmFields\": [\n" + - " {\n" + - " \"type\": \"ALARM_FIELD\",\n" + - " \"key\": \"createdTime\"\n" + - " },\n" + - " {\n" + - " \"type\": \"ALARM_FIELD\",\n" + - " \"key\": \"type\"\n" + - " },\n" + - " {\n" + - " \"type\": \"ALARM_FIELD\",\n" + - " \"key\": \"severity\"\n" + - " },\n" + - " {\n" + - " \"type\": \"ALARM_FIELD\",\n" + - " \"key\": \"status\"\n" + - " }\n" + - " ],\n" + - " \"entityFields\": [\n" + - " {\n" + - " \"type\": \"ENTITY_FIELD\",\n" + - " \"key\": \"name\"\n" + - " }\n" + - " ],\n" + - " \"latestValues\": [\n" + - " {\n" + - " \"type\": \"ATTRIBUTE\",\n" + - " \"key\": \"model\"\n" + - " },\n" + - " {\n" + - " \"type\": \"TIME_SERIES\",\n" + - " \"key\": \"temperature\"\n" + - " }\n" + - " ]\n" + - "}" + - MARKDOWN_CODE_BLOCK_END + - ""; - @Autowired private EntityQueryService entityQueryService; diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 435ac4f89b..f5c5bdd284 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -43,6 +43,11 @@ import org.thingsboard.server.service.security.permission.Operation; import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RELATION_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RELATION_TYPE_GROUP_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RELATION_TYPE_PARAM_DESCRIPTION; @RestController @TbCoreComponent diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java index b323286b7c..2d8e6cf57a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -74,6 +74,11 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION; import static org.thingsboard.server.controller.EdgeController.EDGE_ID; /** diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 68969add27..860671f45e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -40,6 +40,29 @@ import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_DEBUG_RULE_NODE_FILTER_OBJ; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_END_TIME_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_ERROR_FILTER_OBJ; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_LC_EVENT_FILTER_OBJ; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_START_TIME_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_STATS_FILTER_OBJ; +import static org.thingsboard.server.controller.ControllerConstants.EVENT_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java index 072d4125b4..816b8fc849 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java +++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java @@ -36,6 +36,9 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.List; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping("/api/oauth2/config/template") diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java index 3513cb3139..3b323ca411 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java @@ -43,6 +43,8 @@ import javax.servlet.http.HttpServletRequest; import java.util.Enumeration; import java.util.List; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java index 76ca284e53..593914bc4c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java +++ b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java @@ -49,6 +49,22 @@ import org.thingsboard.server.service.security.permission.Resource; import java.nio.ByteBuffer; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + @Slf4j @RestController @TbCoreComponent diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java index d7f59d65ba..c1c57f2d1f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java @@ -32,6 +32,10 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.Set; +import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java index dc8369330a..a2c52d76a2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java @@ -34,6 +34,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.UUID; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + @RestController @TbCoreComponent @RequestMapping(TbUrlConstants.RPC_V1_URL_PREFIX) diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index 447f3c9013..b388f4d7b5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -53,6 +53,8 @@ import java.util.UUID; import static org.thingsboard.server.common.data.DataConstants.RPC_DELETED; +import static org.thingsboard.server.controller.ControllerConstants.*; + @RestController @TbCoreComponent @RequestMapping(TbUrlConstants.RPC_V2_URL_PREFIX) diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 310c9f9216..8996367c36 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -81,6 +81,25 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TYPES_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TYPE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; + @Slf4j @RestController @TbCoreComponent diff --git a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java index 16892fd400..3f083c3572 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java @@ -47,6 +47,22 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.Base64; import java.util.List; +import static org.thingsboard.server.controller.ControllerConstants.LWM2M_OBJECT_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; + @Slf4j @RestController @TbCoreComponent 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 3d6eb09807..bcaa9dac03 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -103,6 +103,14 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + + /** * Created by ashvayka on 22.03.18. */ diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index d5c0b896c3..edde16d6e5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -43,6 +43,21 @@ import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import static org.thingsboard.server.controller.ControllerConstants.HOME_DASHBOARD; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_TEXT_SEARCH_DESCRIPTION; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index e9b95e5d40..a9934c753a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -40,6 +40,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import static org.thingsboard.server.controller.ControllerConstants.*; + @RestController @TbCoreComponent @RequestMapping("/api") diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index 4222e76658..e7171da3b6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -62,6 +62,8 @@ import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.servlet.http.HttpServletRequest; import java.util.List; +import static org.thingsboard.server.controller.ControllerConstants.*; + @RequiredArgsConstructor @RestController @TbCoreComponent diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index a19799444b..35540b3cd2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -28,7 +28,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; @@ -44,6 +43,8 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.List; +import static org.thingsboard.server.controller.ControllerConstants.*; + @Slf4j @RestController @TbCoreComponent diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index 08bd3e3984..747f17c65c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -41,6 +41,8 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.List; +import static org.thingsboard.server.controller.ControllerConstants.*; + @RestController @TbCoreComponent @RequestMapping("/api") From e2f26051979d9f63dd921fe6deb4223331bf134d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 22 Oct 2021 09:53:25 +0300 Subject: [PATCH 117/303] Fix fork join pool - use current classloader for thread context classloader instead of system --- .../queue/kafka/TbKafkaProducerTemplate.java | 3 --- ...hingsBoardForkJoinWorkerThreadFactory.java | 2 +- .../rule/engine/kafka/TbKafkaNode.java | 20 ++----------------- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java index a5aa451bd1..99e9c562a7 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java @@ -62,9 +62,6 @@ public class TbKafkaProducerTemplate implements TbQueuePro } this.settings = settings; - // Ugly workaround to fix org.apache.kafka.common.KafkaException: javax.security.auth.login.LoginException: unable to find LoginModule class - // details: https://stackoverflow.com/questions/57574901/kafka-java-client-classloader-doesnt-find-sasl-scram-login-class - Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); this.producer = new KafkaProducer<>(props); this.defaultTopic = defaultTopic; this.admin = admin; diff --git a/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardForkJoinWorkerThreadFactory.java b/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardForkJoinWorkerThreadFactory.java index 319421f8bc..a4e56d579a 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardForkJoinWorkerThreadFactory.java +++ b/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardForkJoinWorkerThreadFactory.java @@ -34,8 +34,8 @@ public class ThingsBoardForkJoinWorkerThreadFactory implements ForkJoinPool.Fork @Override public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { ForkJoinWorkerThread thread = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); + thread.setContextClassLoader(this.getClass().getClassLoader()); thread.setName(namePrefix +"-"+thread.getPoolIndex()+"-"+threadNumber.getAndIncrement()); return thread; } - } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java index df273dc8f8..49f41762ce 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java @@ -75,8 +75,8 @@ public class TbKafkaNode implements TbNode { Properties properties = new Properties(); properties.put(ProducerConfig.CLIENT_ID_CONFIG, "producer-tb-kafka-node-" + ctx.getSelfId().getId().toString() + "-" + ctx.getServiceId()); properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, config.getBootstrapServers()); - properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, getKafkaSerializerClass(config.getValueSerializer())); - properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, getKafkaSerializerClass(config.getKeySerializer())); + properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, config.getValueSerializer()); + properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, config.getKeySerializer()); properties.put(ProducerConfig.ACKS_CONFIG, config.getAcks()); properties.put(ProducerConfig.RETRIES_CONFIG, config.getRetries()); properties.put(ProducerConfig.BATCH_SIZE_CONFIG, config.getBatchSize()); @@ -88,28 +88,12 @@ public class TbKafkaNode implements TbNode { addMetadataKeyValuesAsKafkaHeaders = BooleanUtils.toBooleanDefaultIfNull(config.isAddMetadataKeyValuesAsKafkaHeaders(), false); toBytesCharset = config.getKafkaHeadersCharset() != null ? Charset.forName(config.getKafkaHeadersCharset()) : StandardCharsets.UTF_8; try { - // Ugly workaround to fix org.apache.kafka.common.KafkaException: javax.security.auth.login.LoginException: unable to find LoginModule class - // details: https://stackoverflow.com/questions/57574901/kafka-java-client-classloader-doesnt-find-sasl-scram-login-class - Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); this.producer = new KafkaProducer<>(properties); } catch (Exception e) { throw new TbNodeException(e); } } - private Class getKafkaSerializerClass(String serializerClassName) { - Class serializerClass = null; - if (!StringUtils.isEmpty(serializerClassName)) { - try { - serializerClass = Class.forName(serializerClassName); - } catch (ClassNotFoundException e) {} - } - if (serializerClass == null) { - serializerClass = StringSerializer.class; - } - return serializerClass; - } - @Override public void onMsg(TbContext ctx, TbMsg msg) { String topic = TbNodeUtils.processPattern(config.getTopicPattern(), msg); From 72d7c0bb299e7c3af5b14273c7632d4760de7e58 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 22 Oct 2021 11:05:11 +0300 Subject: [PATCH 118/303] Improve optional datasources handling --- ui-ngx/src/app/core/api/widget-api.models.ts | 1 + ui-ngx/src/app/core/api/widget-subscription.ts | 5 ++++- .../app/modules/home/components/widget/widget.component.ts | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index ed681129ec..d053efb601 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -235,6 +235,7 @@ export interface WidgetSubscriptionOptions { stateData?: boolean; alarmSource?: Datasource; datasources?: Array; + datasourcesOptional?: boolean; hasDataPageLink?: boolean; singleEntity?: boolean; warnOnPageDataOverflow?: boolean; diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 4152808413..21f95a9158 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -106,6 +106,7 @@ export class WidgetSubscription implements IWidgetSubscription { caulculateLegendData: boolean; displayLegend: boolean; stateData: boolean; + datasourcesOptional: boolean; decimals: number; units: string; comparisonEnabled: boolean; @@ -181,6 +182,7 @@ export class WidgetSubscription implements IWidgetSubscription { this.callbacks.dataLoading = this.callbacks.dataLoading || (() => {}); this.callbacks.timeWindowUpdated = this.callbacks.timeWindowUpdated || (() => {}); this.alarmSource = options.alarmSource; + this.datasourcesOptional = options.datasourcesOptional; this.alarmDataListener = null; this.alarms = emptyPageData(); this.originalTimewindow = null; @@ -212,6 +214,7 @@ export class WidgetSubscription implements IWidgetSubscription { this.callbacks.timeWindowUpdated = this.callbacks.timeWindowUpdated || (() => {}); this.configuredDatasources = this.ctx.utils.validateDatasources(options.datasources); + this.datasourcesOptional = options.datasourcesOptional; this.entityDataListeners = []; this.hasDataPageLink = options.hasDataPageLink; this.singleEntity = options.singleEntity; @@ -448,7 +451,7 @@ export class WidgetSubscription implements IWidgetSubscription { } }); this.configureLoadedData(); - this.hasResolvedData = this.datasources.length > 0; + this.hasResolvedData = this.datasources.length > 0 || this.datasourcesOptional; this.updateDataTimewindow(); this.notifyDataLoaded(); this.onDataUpdated(true); diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 941b603dcc..920f6721b9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -936,6 +936,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI options = { type: this.widget.type, stateData: this.typeParameters.stateData, + datasourcesOptional: this.typeParameters.datasourcesOptional, hasDataPageLink: this.typeParameters.hasDataPageLink, singleEntity: this.typeParameters.singleEntity, warnOnPageDataOverflow: this.typeParameters.warnOnPageDataOverflow, From 33c6aeccff507d01cae858b6c5d132c37f1cfe33 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Fri, 22 Oct 2021 11:27:31 +0300 Subject: [PATCH 119/303] additional improvements to the docs of the event controller (event filters) --- .../controller/ControllerConstants.java | 52 +++++++++++++++---- .../server/controller/EventController.java | 41 ++++++++++++--- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index c63f6178c7..82b293342c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -130,17 +130,47 @@ public class ControllerConstants { protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n"; protected static final String MARKDOWN_CODE_BLOCK_END = "\n```"; - protected static final String EVENT_ERROR_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"ERROR\", \"server\": \"ip-172-31-24-152\", " + - "\"method\": \"onClusterEventMsg\", \"error\": \"Error Message\" }" + MARKDOWN_CODE_BLOCK_END; - protected static final String EVENT_LC_EVENT_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"LC_EVENT\", \"server\": \"ip-172-31-24-152\", \"event\":" + - " \"STARTED\", \"status\": \"Success\", \"error\": \"Error Message\" }" + MARKDOWN_CODE_BLOCK_END; - protected static final String EVENT_STATS_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"STATS\", \"server\": \"ip-172-31-24-152\", \"messagesProcessed\": 10, \"errorsOccurred\": 5 }" + MARKDOWN_CODE_BLOCK_END; - protected static final String DEBUG_FILTER_OBJ = "\"msgDirectionType\": \"IN\", \"server\": \"ip-172-31-24-152\", \"dataSearch\": \"humidity\", " + - "\"metadataSearch\": \"deviceName\", \"entityName\": \"DEVICE\", \"relationType\": \"Success\"," + - " \"entityId\": \"de9d54a0-2b7a-11ec-a3cc-23386423d98f\", \"msgType\": \"POST_TELEMETRY_REQUEST\"," + - " \"isError\": \"false\", \"error\": \"Error Message\" }"; - protected static final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; - protected static final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; + protected static final String EVENT_ERROR_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"eventType\":\"ERROR\",\n" + + " \"server\":\"ip-172-31-24-152\",\n" + + " \"method\":\"onClusterEventMsg\",\n" + + " \"errorStr\":\"Error Message\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + protected static final String EVENT_LC_EVENT_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"eventType\":\"LC_EVENT\",\n" + + " \"server\":\"ip-172-31-24-152\",\n" + + " \"event\":\"STARTED\",\n" + + " \"status\":\"Success\",\n" + + " \"errorStr\":\"Error Message\"\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + protected static final String EVENT_STATS_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"eventType\":\"STATS\",\n" + + " \"server\":\"ip-172-31-24-152\",\n" + + " \"messagesProcessed\":10,\n" + + " \"errorsOccurred\":5\n" + + "}" + + MARKDOWN_CODE_BLOCK_END; + protected static final String DEBUG_FILTER_OBJ = + " \"msgDirectionType\":\"IN\",\n" + + " \"server\":\"ip-172-31-24-152\",\n" + + " \"dataSearch\":\"humidity\",\n" + + " \"metadataSearch\":\"deviceName\",\n" + + " \"entityName\":\"DEVICE\",\n" + + " \"relationType\":\"Success\",\n" + + " \"entityId\":\"de9d54a0-2b7a-11ec-a3cc-23386423d98f\",\n" + + " \"msgType\":\"POST_TELEMETRY_REQUEST\",\n" + + " \"isError\":\"false\",\n" + + " \"errorStr\":\"Error Message\"\n" + + "}"; + protected static final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{\n" + + " \"eventType\":\"DEBUG_RULE_NODE\",\n" + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; + protected static final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{\n" + + " \"eventType\":\"DEBUG_RULE_CHAIN\",\n" + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + "Provides a hint about the data type of the entity field that is defined in the filter key. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 860671f45e..d1e9ad8efc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -68,6 +68,37 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PA @RequestMapping("/api") public class EventController extends BaseController { + private static final String EVENT_FILTER_DEFINITION = "# Event Filter Definition" + NEW_LINE + + "5 different eventFilter objects could be set for different event types. " + + "The eventType field is required. Others are optional. If some of them are set, the filtering will be applied according to them. " + + "See the examples below for all the fields used for each event type filtering. " + NEW_LINE + + "Note," + NEW_LINE + + " * 'server' - string value representing the server name, identifier or ip address where the platform is running;\n" + + " * 'errorStr' - the case insensitive 'contains' filter based on error message." + NEW_LINE + + "## Error Event Filter" + NEW_LINE + + EVENT_ERROR_FILTER_OBJ + NEW_LINE + + " * 'method' - string value representing the method name when the error happened." + NEW_LINE + + "## Lifecycle Event Filter" + NEW_LINE + + EVENT_LC_EVENT_FILTER_OBJ + NEW_LINE + + " * 'event' - string value representing the lifecycle event type;\n" + + " * 'status' - string value representing status of the lifecycle event." + NEW_LINE + + "## Statistics Event Filter" + NEW_LINE + + EVENT_STATS_FILTER_OBJ + NEW_LINE + + " * 'messagesProcessed' - the minimum number of successfully processed messages;\n" + + " * 'errorsOccurred' - the minimum number of errors occurred during messages processing." + NEW_LINE + + "## Debug Rule Node Event Filter" + NEW_LINE + + EVENT_DEBUG_RULE_NODE_FILTER_OBJ + NEW_LINE + + "## Debug Rule Chain Event Filter" + NEW_LINE + + EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ + NEW_LINE + + " * 'msgDirectionType' - string value representing msg direction type (incoming to entity or outcoming from entity);\n" + + " * 'dataSearch' - the case insensitive 'contains' filter based on data (key and value) for the message;\n" + + " * 'metadataSearch' - the case insensitive 'contains' filter based on metadata (key and value) for the message;\n" + + " * 'entityName' - string value representing the entity type;\n" + + " * 'relationType' - string value representing the type of message routing;\n" + + " * 'entityId' - string value representing the entity id in the event body (originator of the message);\n" + + " * 'msgType' - string value representing the message type;\n" + + " * 'isError' - boolean value to filter the errors." + NEW_LINE; + @Autowired private EventService eventService; @@ -159,14 +190,8 @@ public class EventController extends BaseController { @ApiOperation(value = "Get Events by event filter (getEvents)", notes = "Returns a page of events for the chosen entity by specifying the event filter. " + - PAGE_DATA_PARAMETERS + NEW_LINE + "5 different eventFilter objects could be set for different event types. " + - "The eventType field is required. Others are optional. If some of them are set, the filtering will be applied according to them. " + - "See the examples below for all the fields used for each event type filtering. " + NEW_LINE + - EVENT_ERROR_FILTER_OBJ + NEW_LINE + - EVENT_LC_EVENT_FILTER_OBJ + NEW_LINE + - EVENT_STATS_FILTER_OBJ + NEW_LINE + - EVENT_DEBUG_RULE_NODE_FILTER_OBJ + NEW_LINE + - EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ + NEW_LINE, + PAGE_DATA_PARAMETERS + NEW_LINE + + EVENT_FILTER_DEFINITION, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.POST) From 07dca7ef6391f35d6c17d4437750aca8c4ad82cc Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 22 Oct 2021 13:27:55 +0300 Subject: [PATCH 120/303] Improve markdown tokenizer --- .../components/marked-options.service.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ui-ngx/src/app/shared/components/marked-options.service.ts b/ui-ngx/src/app/shared/components/marked-options.service.ts index 1666ca590e..0aab6b0aa2 100644 --- a/ui-ngx/src/app/shared/components/marked-options.service.ts +++ b/ui-ngx/src/app/shared/components/marked-options.service.ts @@ -19,6 +19,8 @@ import { Inject, Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { DOCUMENT } from '@angular/common'; import { WINDOW } from '@core/services/window.service'; +import { Tokenizer } from 'marked'; +import * as marked from 'marked'; const copyCodeBlock = '{:copy-code}'; const autoBlock = '{:auto}'; @@ -37,6 +39,7 @@ export class MarkedOptionsService extends MarkedOptions { pedantic = false; smartLists = true; smartypants = false; + mangle = false; private renderer2 = new MarkedRenderer(); @@ -46,6 +49,26 @@ export class MarkedOptionsService extends MarkedOptions { @Inject(WINDOW) private readonly window: Window, @Inject(DOCUMENT) private readonly document: Document) { super(); + // @ts-ignore + const tokenizer: Tokenizer = { + autolink(src: string, mangle: (cap: string) => string): marked.Tokens.Link { + if (src.endsWith(copyCodeBlock)) { + return undefined; + } else { + // @ts-ignore + return false; + } + }, + url(src: string, mangle: (cap: string) => string): marked.Tokens.Link { + if (src.endsWith(copyCodeBlock)) { + return undefined; + } else { + // @ts-ignore + return false; + } + } + }; + marked.use({tokenizer}); this.renderer.code = (code: string, language: string | undefined, isEscaped: boolean) => { if (code.endsWith(copyCodeBlock)) { code = code.substring(0, code.length - copyCodeBlock.length); From fabfcc9096570960641c51ac7d2ffde70cc9c1dc Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 22 Oct 2021 19:51:49 +0300 Subject: [PATCH 121/303] Improve help popup button to work in disabled fieldsets --- .../components/help-popup.component.html | 55 ++++++++++--------- .../components/help-popup.component.scss | 7 +++ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/ui-ngx/src/app/shared/components/help-popup.component.html b/ui-ngx/src/app/shared/components/help-popup.component.html index fde1fc8a87..a401459198 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.html +++ b/ui-ngx/src/app/shared/components/help-popup.component.html @@ -15,28 +15,33 @@ limitations under the License. --> - - +
    +
    + +
    +
    + +
    +
    diff --git a/ui-ngx/src/app/shared/components/help-popup.component.scss b/ui-ngx/src/app/shared/components/help-popup.component.scss index e28445de66..7b7de2f022 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.scss +++ b/ui-ngx/src/app/shared/components/help-popup.component.scss @@ -13,6 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +.tb-help-popup-button-container { + width: initial; + display: inline-block; + vertical-align: middle; +} + .tb-help-popup-button { position: relative; .mat-progress-spinner { From b658fafee288b590330e1f48be6af1d072935cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=9F=93?= Date: Sun, 24 Oct 2021 09:06:28 +0800 Subject: [PATCH 122/303] Update locale.constant-zh_CN.json --- .../assets/locale/locale.constant-zh_CN.json | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index cb135a221a..270fd6ad4e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -1924,6 +1924,68 @@ "sign-in": "登录 ", "username": "用户名(电子邮件)" }, + "ota-update": { + "add": "添加包", + "assign-firmware": "分配的固件", + "assign-firmware-required": "分配的固件必填", + "assign-software": "分配的软件", + "assign-software-required": "分配的软件必填", + "auto-generate-checksum": "自动生成校验和", + "checksum": "校验和", + "checksum-hint": "如果校验和为空,会自动生成", + "checksum-algorithm": "校验和算法", + "checksum-copied-message": "包校验和已复制到剪贴板", + "change-firmware": "固件的更改可能会导致 { count, plural, 1 {1 个设备} other {# 个设备} } 的更新。", + "change-software": "软件的更改可能会导致 { count, plural, 1 {1 个设备} other {# 个设备} } 的更新。", + "chose-compatible-device-profile": "上传的包仅适用于具有所选配置文件的设备。", + "chose-firmware-distributed-device": "选择将分发到设备的固件", + "chose-software-distributed-device": "选择将分发到设备的软件", + "content-type": "内容类型", + "copy-checksum": "复制校验和", + "copy-direct-url": "复制直接URL", + "copyId": "复制包ID", + "copied": "已复制!", + "delete": "删除包", + "delete-ota-update-text": "小心,OTA升级确认后不可恢复。", + "delete-ota-update-title": "您确定要删除OTA升级'{{title}}'吗?", + "delete-ota-updates-text": "小心,确认后所有选中的OTA升级将被删除。", + "delete-ota-updates-title": "您确定要删除 { count, plural, 1 {1 OTA升级} other {# OTA升级} } 吗?", + "description": "描述", + "direct-url": "直接URL", + "direct-url-copied-message": "包直接URL已复制到剪贴板", + "direct-url-required": "直接URL必填", + "download": "下载包", + "drop-file": "拖放打包文件或点击选择要上传的文件。", + "file-name": "文件名", + "file-size": "文件大小", + "file-size-bytes": "文件大小(以字节为单位)", + "idCopiedMessage": "包ID已被复制到剪贴板", + "no-firmware-matching": "没有找到与'{{entity}}'匹配的兼容固件OTA升级包。", + "no-firmware-text": "没有提供兼容的固件OTA升级包。", + "no-packages-text": "没有找到包", + "no-software-matching": "没有找到匹配 '{{entity}}' 的兼容软件OTA升级包。", + "no-software-text": "没有提供兼容的软件OTA升级包。", + "ota-update": "OTA 升级", + "ota-update-details": "OTA 升级详情", + "ota-updates": "OTA 升级", + "package-type": "包类型", + "packages-repository": "包仓库", + "search": "搜索包", + "selected-package": "{ count, plural, 1 {1 个包} other {# 个包} } 选中", + "title": "标题", + "title-required": "标题必填。", + "types": { + "firmware": "固件", + "software": "软件" + }, + "upload-binary-file": "上传二进制文件", + "use-external-url": "使用外部URL", + "version": "版本", + "version-required": "版本必填。", + "version-tag": "版本标签", + "version-tag-hint": "自定义标签应与您设备报告的软件包版本相匹配。", + "warning-after-save-no-edit": "上传包后,您将无法修改标题、版本、设备配置文件和包类型。" + }, "position": { "bottom": "底部", "left": "左侧", From 266cdae02f6ece4b226784c6e90c06664346fdd8 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 22 Oct 2021 17:41:05 +0300 Subject: [PATCH 123/303] UI: Fixed gauge widgets incorrect display after work some time --- ui-ngx/patches/canvas-gauges+2.1.7.patch | 13 +++++++++++++ .../components/widget/lib/canvas-digital-gauge.ts | 12 ++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 ui-ngx/patches/canvas-gauges+2.1.7.patch diff --git a/ui-ngx/patches/canvas-gauges+2.1.7.patch b/ui-ngx/patches/canvas-gauges+2.1.7.patch new file mode 100644 index 0000000000..7f83155d41 --- /dev/null +++ b/ui-ngx/patches/canvas-gauges+2.1.7.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/canvas-gauges/gauge.min.js b/node_modules/canvas-gauges/gauge.min.js +index 6aea775..d9fe5d3 100644 +--- a/node_modules/canvas-gauges/gauge.min.js ++++ b/node_modules/canvas-gauges/gauge.min.js +@@ -23,5 +23,5 @@ + * + * @version 2.1.7 + */ +-!function(e){"use strict";function t(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t1&&(d=1),1!==d&&(c=r(d),isFinite(c)&&!isNaN(c)&&(d=c)),t&&t(d),s0){for(a=e.toFixed(i).toString().split("."),n=r-a[0].length;o1?(r=~i.indexOf("."),~i.indexOf("-")?"-"+[t.majorTicksInt+t.majorTicksDec+2+(r?1:0)-i.length].join("0")+i.replace("-",""):[t.majorTicksInt+t.majorTicksDec+1+(r?1:0)-i.length].join("0")+i):i}function m(e){return e*Math.PI/180}function v(e,t){return{x:-e*Math.sin(t),y:e*Math.cos(t)}}function g(e,t,i,r){var o=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],n=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,a=e.createLinearGradient(o?0:n,o?n:0,o?0:r,o?r:0);return a.addColorStop(0,t),a.addColorStop(1,i),a}function b(e,t){if(arguments.length>2&&void 0!==arguments[2]&&arguments[2])return e.restore(),!0;e.save();var i=t.borderShadowWidth;return i&&(e.shadowBlur=i,e.shadowColor=t.colorBorderShadow),!0}function p(e,t){t.needleShadow&&(e.shadowOffsetX=2,e.shadowOffsetY=2,e.shadowBlur=10,e.shadowColor=t.colorNeedleShadowDown)}function w(e,t,i){return e["font"+t+"Style"]+" "+e["font"+t+"Weight"]+" "+e["font"+t+"Size"]*i+"px "+e["font"+t]}function k(e){e.shadowOffsetX=null,e.shadowOffsetY=null,e.shadowBlur=null,e.shadowColor="",e.strokeStyle=null,e.lineWidth=0,e.save()}function y(e,t,i,r){t.valueTextShadow&&(e.shadowOffsetX=i,e.shadowOffsetY=i,e.shadowBlur=r,e.shadowColor=t.colorValueTextShadow)}function x(e,t,i,r,o,n){if(t.valueBox){k(e);var a=t.valueDec?1+t.valueDec:0,l="9".repeat(Math.max.apply(null,[String(parseInt(i)).length+a].concat(t.majorTicks.map(function(e){return String(parseInt(e,10)).length+a})))),s=t.valueText||u(i,t),d=n/200,c=n/100,f=.4*c,m=1.2*c;e.font=w(t,"Value",d),y(e,t,f,m);var v=e.measureText(t.valueText?s:"-"+u(Number(l),t)).width;k(e);var g=parseFloat(t.fontValueSize)*d+f+m,b=c*parseFloat(t.valueBoxStroke),p=2*n-2*b,x=v+10*c,T=1.1*g+f+m,S=c*t.valueBoxBorderRadius,V=(parseFloat(t.valueBoxWidth)||0)/100*p;V>x&&(x=V),x>p&&(x=p);var W=r-x/2,O=o-T/2,A=o-5.75*c;if(e.beginPath(),S?h(e,W,O,x,T,S):e.rect(W,O,x,T),b){var P=e.createRadialGradient(r,A,10*c,r,A,20*c);P.addColorStop(0,t.colorValueBoxRect),P.addColorStop(1,t.colorValueBoxRectEnd),e.strokeStyle=P,e.lineWidth=b,e.stroke()}t.colorValueBoxShadow&&(e.shadowBlur=1.2*c,e.shadowColor=t.colorValueBoxShadow),t.colorValueBoxBackground&&(e.fillStyle=t.colorValueBoxBackground,e.fill()),e.closePath(),e.restore(),y(e,t,f,m),e.fillStyle=t.colorValueText,e.textAlign="center",e.textBaseline="alphabetic",e.fillText(s,W+x/2,o+T/2-g/3),e.restore()}}function T(e){var t=e.value,i=e.minValue,r=e.maxValue,o=.01*(r-i);return{normal:tr?r:t,indented:tr?r+o:t}}function S(e,t,i,r,o){i.beginPath(),i.arc(0,0,xe(e),0,2*Oe,!0),i.lineWidth=t,i.strokeStyle=o?We.linearGradient(i,r,o,e):r,i.stroke(),i.closePath()}function V(e,t){var i=pe.pixelRatio;return e.maxRadius||(e.maxRadius=e.max-t.borderShadowWidth-t.borderOuterWidth*i-t.borderMiddleWidth*i-t.borderInnerWidth*i+(t.borderOuterWidth?.5:0)+(t.borderMiddleWidth?.5:0)+(t.borderInnerWidth?.5:0)),e.maxRadius}function W(e,t){var i=pe.pixelRatio,r=t.borderShadowWidth*i,o=e.max-r-t.borderOuterWidth*i/2,n=o-t.borderOuterWidth*i/2-t.borderMiddleWidth*i/2+.5,a=n-t.borderMiddleWidth*i/2-t.borderInnerWidth*i/2+.5,l=V(e,t),s=void 0,d=!1;e.save(),t.borderOuterWidth&&(d=We.drawShadow(e,t,d),S(o,t.borderOuterWidth*i,e,t.colorBorderOuter,t.colorBorderOuterEnd)),t.borderMiddleWidth&&(d=We.drawShadow(e,t,d),S(n,t.borderMiddleWidth*i,e,t.colorBorderMiddle,t.colorBorderMiddleEnd)),t.borderInnerWidth&&(d=We.drawShadow(e,t,d),S(a,t.borderInnerWidth*i,e,t.colorBorderInner,t.colorBorderInnerEnd)),We.drawShadow(e,t,d),e.beginPath(),e.arc(0,0,xe(l),0,2*Oe,!0),t.colorPlateEnd?(s=e.createRadialGradient(0,0,l/2,0,0,l),s.addColorStop(0,t.colorPlate),s.addColorStop(1,t.colorPlateEnd)):s=t.colorPlate,e.fillStyle=s,e.fill(),e.closePath(),e.restore()}function O(e,t){var i=e.max*(parseFloat(t.highlightsWidth)||0)/100;if(i){var r=xe(P(e,t)-i/2),o=0,n=t.highlights.length,a=(t.maxValue-t.minValue)/t.ticksAngle;for(e.save();on?o:n,n>o,o>n?i:r):a,t>0?We.roundRect(e,i,r,o,n,t):e.rect(i,r,o,n),e.fill(),e.closePath()}function G(e,t,i,r,o,n,a,l,s){e.beginPath(),e.lineWidth=t,e.strokeStyle=s?We.linearGradient(e,l,s,a,!0,o):l,i>0?We.roundRect(e,r,o,n,a,i):e.rect(r,o,n,a),e.stroke(),e.closePath()}function F(e,t,i,r,o,n){var a=pe.pixelRatio;e.save();var l=t.borderRadius*a,s=o-t.borderShadowWidth-t.borderOuterWidth*a,d=s-t.borderOuterWidth*a-t.borderMiddleWidth*a,c=d-t.borderMiddleWidth*a-t.borderInnerWidth*a,h=c-t.borderInnerWidth*a,u=n-t.borderShadowWidth-t.borderOuterWidth*a,f=u-t.borderOuterWidth*a-t.borderMiddleWidth*a,m=f-t.borderMiddleWidth*a-t.borderInnerWidth*a,v=m-t.borderInnerWidth*a,g=i-(d-s)/2,b=g-(c-d)/2,p=b-(h-c)/2,w=r-(f-u)/2,k=w-(m-f)/2,y=k-(v-m)/2,x=0,T=!1;return t.borderOuterWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderOuterWidth*a,l,i+t.borderOuterWidth*a/2-x,r+t.borderOuterWidth*a/2-x,s,u,t.colorBorderOuter,t.colorBorderOuterEnd),x+=.5*a),t.borderMiddleWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderMiddleWidth*a,l-=1+2*x,g+t.borderMiddleWidth*a/2-x,w+t.borderMiddleWidth*a/2-x,d+2*x,f+2*x,t.colorBorderMiddle,t.colorBorderMiddleEnd),x+=.5*a),t.borderInnerWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderInnerWidth*a,l-=1+2*x,b+t.borderInnerWidth*a/2-x,k+t.borderInnerWidth*a/2-x,c+2*x,m+2*x,t.colorBorderInner,t.colorBorderInnerEnd),x+=.5*a),We.drawShadow(e,t,T),L(e,l,p,y,h+2*x,v+2*x,t.colorPlate,t.colorPlateEnd),e.restore(),[p,y,h,v]}function X(e,t,i,r,o,n){var a=pe.pixelRatio,l=n>=o,s=l?.85*o:n,d=l?n:o;i=l?ye(i+(o-s)/2):i;var c=!!t.title,h=!!t.units,u=!!t.valueBox,f=void 0,m=void 0,v=void 0;l?(m=ye(.05*d),f=ye(.075*d),v=ye(.11*d),c&&(d-=f,r+=f),h&&(d-=m),u&&(d-=v)):(m=f=ye(.15*s),c&&(s-=f,r+=f),h&&(s-=m));var g=2*t.barStrokeWidth,b=t.barBeginCircle?ye(s*t.barBeginCircle/200-g/2):0,p=ye(s*t.barWidth/100-g),w=ye(d*t.barLength/100-g),k=ye((d-w)/2),y=ye(i+(l?s/2:k+b)),x=ye(r+(l?d-k-b+g/2:s/2)),T=!l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s,S=l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s;return e.barDimensions={isVertical:l,width:s,length:d,barWidth:p,barLength:w,strokeWidth:g,barMargin:k,radius:b,pixelRatio:a,barOffset:null,titleMargin:c?f:0,unitsMargin:h?m:0,get ticksLength(){return this.barLength-this.barOffset-this.strokeWidth},X:i+T,Y:r+S,x0:y+T,y0:x+S,baseX:i,baseY:r,ticksPadding:t.ticksPadding/100},e.barDimensions}function Y(e,t,i,r,o,n,a){var l=X(e,t,r,o,n,a),s=l.isVertical,d=l.width,c=l.barWidth,h=l.barLength,u=l.strokeWidth,f=l.barMargin,m=l.radius,v=l.x0,g=l.y0,b=l.X,p=l.Y,w=h;if(e.save(),e.beginPath(),t.barBeginCircle){var k=We.radians(s?270:0),y=Math.asin(c/2/m),x=Math.cos(y),T=Math.sin(y),S=v+(s?m*T:m*x-u/2),V=s?g-m*x:g+m*T,W=xe(s?V-g:S-v);e.barDimensions.barOffset=ye(W+m);var O=s?ye(v-m*T):S,A=s?V:ye(g-m*T);"progress"===i&&(h=e.barDimensions.barOffset+(h-e.barDimensions.barOffset)*(We.normalizedValue(t).normal-t.minValue)/(t.maxValue-t.minValue));var P=ye(S+h-e.barDimensions.barOffset+u/2),M=ye(V-h+e.barDimensions.barOffset-u/2);e.arc(v,g,m,k+y,k-y),s?(e.moveTo(S,A),e.lineTo(S,M),e.lineTo(O,M),e.lineTo(O,A)):(e.moveTo(S,A),e.lineTo(P,A),e.lineTo(P,V),e.lineTo(S,V))}else{var B=ye(s?b+(d-c)/2:b+f),C=ye(s?p+h+f:p+(d-c)/2);"progress"===i&&(h*=(t.value-t.minValue)/(t.maxValue-t.minValue)),s?e.rect(B,C,c,-h):e.rect(B,C,h,c)}"progress"!==i&&t.barStrokeWidth&&(e.lineWidth=u,e.strokeStyle=t.colorBarStroke,e.stroke()),"progress"!==i&&t.colorBar?(e.fillStyle=t.colorBarEnd?We.linearGradient(e,t.colorBar,t.colorBarEnd,h,s,s?p:b):t.colorBar,e.fill()):"progress"===i&&t.colorBarProgress&&(e.fillStyle=t.colorBarProgressEnd?We.linearGradient(e,t.colorBarProgress,t.colorBarProgressEnd,w,s,s?p:b):t.colorBarProgress,e.fill()),e.closePath(),t.barBeginCircle&&(e.barDimensions.radius+=u),e.barDimensions.barWidth+=u,e.barDimensions.barLength+=u}function U(e,t,i,r,o,n){Y(e,t,"",i,r,o,n)}function q(e,t){return t.needleSide!==e||t.tickSide!==e||t.numberSide!==e}function H(e,t,i,r,o,n){t.barProgress&&Y(e,t,"progress",i,r,o,n)}function J(e,t){var i=e.barDimensions,r=i.isVertical,o=i.width,n=i.length,a=i.barWidth,l=i.barOffset,s=i.barMargin,d=i.X,c=i.Y,h=i.ticksLength,u=i.ticksPadding,f=o*(parseFloat(t.highlightsWidth)||0)/100;if(t.highlights&&f){var m="right"!==t.tickSide,v="left"!==t.tickSide,g=0,b=t.highlights.length,p=(o-a)/2,w=t.maxValue-t.minValue,k=ye(r?d+p:d+s+l),y=f,x=r?c+n-s-l:c+p,T=ye((t.ticksWidth/100+u)*o)+(f-t.ticksWidth/100*o),S=ye(a+u*o);for(e.save();gn&&(d*=-1),e.moveTo(i-h,r),e.lineTo(i+h,r),e.lineTo(i+h,r+d),e.lineTo(i,n),e.lineTo(i-h,r+d),e.lineTo(i-h,r)):(i>o&&(d*=-1),e.moveTo(i,r-h),e.lineTo(i,r+h),e.lineTo(i+d,r+h),e.lineTo(o,r),e.lineTo(i+d,r-h),e.lineTo(i,r-h)),e.fill(),e.closePath()}function se(e,t,i,r,o,n,a){var l=(parseFloat(t.fontValueSize)||0)*n/200,s=(.11*a-l)/2;e.barDimensions.isVertical&&We.drawValueBox(e,t,i,r+n/2,o+a-l-s,n)}var de=function(){function e(e,t){var i=[],r=!0,o=!1,n=void 0;try{for(var a,l=e[Symbol.iterator]();!(r=(a=l.next()).done)&&(i.push(a.value),!t||i.length!==t);r=!0);}catch(e){o=!0,n=e}finally{try{!r&&l.return&&l.return()}finally{if(o)throw n}}return i}return function(t,i){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),ce=function e(t,i,r){null===t&&(t=Function.prototype);var o=Object.getOwnPropertyDescriptor(t,i);if(void 0===o){var n=Object.getPrototypeOf(t);return null===n?void 0:e(n,i,r)}if("value"in o)return o.value;var a=o.get;if(void 0!==a)return a.call(r)},he=function e(t,i,r,o){var n=Object.getOwnPropertyDescriptor(t,i);if(void 0===n){var a=Object.getPrototypeOf(t);null!==a&&e(a,i,r,o)}else if("value"in n&&n.writable)n.value=r;else{var l=n.set;void 0!==l&&l.call(o,r)}return r},ue=function(){function e(e,t){for(var i=0;i>>0;if(0===o)return-1;var n=+t||0;if(Math.abs(n)===1/0&&(n=0),n>=o)return-1;for(i=Math.max(n>=0?n:o-Math.abs(n),0);i>>0,r=arguments[1],o=r>>0,n=o<0?Math.max(i+o,0):Math.min(o,i),a=arguments[2],l=void 0===a?i:a>>0,s=l<0?Math.max(i+l,0):Math.min(l,i);n1?r-1:0),n=1;n1?t-1:0),r=1;r=(7-4*t)/11)return-Math.pow((11-6*t-11*e)/4,2)+Math.pow(i,2)},elastic:function(e){return 1-ve.delastic(1-e)},delastic:function(e){return Math.pow(2,10*(e-1))*Math.cos(20*Math.PI*1.5/3*e)}},ge=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"linear",i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:250,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){};if(o(this,e),this.duration=i,this.rule=t,this.draw=r,this.end=n,"function"!=typeof this.draw)throw new TypeError("Invalid animation draw callback:",r);if("function"!=typeof this.end)throw new TypeError("Invalid animation end callback:",n)}return ue(e,[{key:"animate",value:function(e,t){var i=this;this.frame&&this.cancel();var r=window.performance&&window.performance.now?window.performance.now():n("animationStartTime")||Date.now();e=e||this.draw,t=t||this.end,this.draw=e,this.end=t,this.frame=me(function(o){return a(o,e,r,ve[i.rule]||i.rule,i.duration,t,i)})}},{key:"cancel",value:function(){if(this.frame){(n("cancelAnimationFrame")||function(e){})(this.frame),this.frame=null}}},{key:"destroy",value:function(){this.cancel(),this.draw=null,this.end=null}}]),e}();ge.rules=ve;var be=function(){function t(i,r,n){o(this,t),this.options=i,this.element=r.toLowerCase(),this.type=t.toDashed(n),this.Type=e[n],this.mutationsObserved=!1,this.isObservable=!!window.MutationObserver,window.GAUGES_NO_AUTO_INIT||t.domReady(this.traverse.bind(this))}return ue(t,[{key:"isValidNode",value:function(e){return!(!e.tagName||e.tagName.toLowerCase()!==this.element||e.getAttribute("data-type")!==this.type)}},{key:"traverse",value:function(){for(var e=document.getElementsByTagName(this.element),t=0,i=e.length;t1&&void 0!==arguments[1])||arguments[1],i=e.split(/-/),r=0,o=i.length,n="";r1&&void 0!==arguments[1]?arguments[1]:0;return e=parseFloat(e),!isNaN(e)&&isFinite(e)||(e=parseFloat(t)||0),e}},{key:"mod",value:function(e,t){return(e%t+t)%t}},{key:"version",get:function(){return ke}}]),n}(fe);void 0!==e&&(e.BaseGauge=Se,e.gauges=(window.document||{}).gauges=Te);var Ve=/{([_a-zA-Z]+[_a-zA-Z0-9]*)}/g,We={roundRect:h,padValue:u,formatMajorTickNumber:f,radians:m,radialPoint:v,linearGradient:g,drawNeedleShadow:p,drawValueBox:x,verifyError:s,prepareTicks:c,drawShadow:b,font:w,normalizedValue:T,formatContext:d},Oe=Math.PI,Ae=Oe/2,Pe=Object.assign({},we,{ticksAngle:270,startAngle:45,colorNeedleCircleOuter:"#f0f0f0",colorNeedleCircleOuterEnd:"#ccc",colorNeedleCircleInner:"#e8e8e8",colorNeedleCircleInnerEnd:"#f5f5f5",needleCircleSize:10,needleCircleInner:!0,needleCircleOuter:!0,needleStart:20,animationTarget:"needle",useMinPath:!1,barWidth:0,barStartPosition:"left"}),Me=function(e){function t(e){return o(this,t),e=Object.assign({},Pe,e||{}),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,t.configure(e)))}return r(t,e),ue(t,[{key:"draw",value:function(){try{var e=this.canvas,i=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],r=i[0],o=i[1],n=i[2],a=i[3],l=this.options;if("needle"===l.animationTarget){if(!e.elementClone.initialized){var s=e.contextClone;s.clearRect(r,o,n,a),s.save(),this.emit("beforePlate"),W(s,l),this.emit("beforeHighlights"),O(s,l),this.emit("beforeMinorTicks"),A(s,l),this.emit("beforeMajorTicks"),M(s,l),this.emit("beforeNumbers"),j(s,l),this.emit("beforeTitle"),N(s,l),this.emit("beforeUnits"),E(s,l),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(r,o,n,a),e.context.save(),e.context.drawImage(e.elementClone,r,o,n,a),e.context.save(),this.emit("beforeProgressBar"),D(e.context,l),this.emit("beforeValueBox"),R(e.context,l,z(this)),this.emit("beforeNeedle"),_(e.context,l)}else{var d=-We.radians((l.value-l.minValue)/(l.maxValue-l.minValue)*l.ticksAngle);if(e.context.clearRect(r,o,n,a),e.context.save(),this.emit("beforePlate"),W(e.context,l),e.context.rotate(d),this.emit("beforeHighlights"),O(e.context,l),this.emit("beforeMinorTicks"),A(e.context,l),this.emit("beforeMajorTicks"),M(e.context,l),this.emit("beforeNumbers"),j(e.context,l),this.emit("beforeProgressBar"),D(e.context,l),e.context.rotate(-d),e.context.save(),!e.elementClone.initialized){var c=e.contextClone;c.clearRect(r,o,n,a),c.save(),this.emit("beforeTitle"),N(c,l),this.emit("beforeUnits"),E(c,l),this.emit("beforeNeedle"),_(c,l),e.elementClone.initialized=!0}e.context.drawImage(e.elementClone,r,o,n,a)}this.emit("beforeValueBox"),R(e.context,l,z(this)),ce(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"draw",this).call(this)}catch(e){We.verifyError(e)}return this}},{key:"value",set:function(e){e=Se.ensureValue(e,this.options.minValue),this.options.animation&&360===this.options.ticksAngle&&this.options.useMinPath&&(this._value=e,e=this.options.value+((e-this.options.value)%360+540)%360-180),he(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"value",e,this)},get:function(){return ce(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"value",this)}}],[{key:"configure",value:function(e){return e.barWidth>50&&(e.barWidth=50),isNaN(e.startAngle)&&(e.startAngle=45),isNaN(e.ticksAngle)&&(e.ticksAngle=270),e.ticksAngle>360&&(e.ticksAngle=360),e.ticksAngle<0&&(e.ticksAngle=0),e.startAngle<0&&(e.startAngle=0),e.startAngle>360&&(e.startAngle=360),e}}]),t}(Se);void 0!==e&&(e.RadialGauge=Me),Se.initialize("RadialGauge",Pe);var Be=Object.assign({},we,{borderRadius:0,barBeginCircle:30,colorBarEnd:"",colorBarProgressEnd:"",needleWidth:6,tickSide:"both",needleSide:"both",numberSide:"both",ticksWidth:10,ticksWidthMinor:5,ticksPadding:5,barLength:85,fontTitleSize:26,highlightsWidth:10}),Ce=function(e){function n(e){return o(this,n),e=Object.assign({},Be,e||{}),i(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n.configure(e)))}return r(n,e),ue(n,[{key:"draw",value:function(){try{var e=this.canvas,i=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],r=i[0],o=i[1],a=i[2],l=i[3],s=this.options;if(!e.elementClone.initialized){var d=e.contextClone;d.clearRect(r,o,a,l),d.save(),this.emit("beforePlate"),this.drawBox=F(d,s,r,o,a,l),this.emit("beforeBar"),U.apply(void 0,[d,s].concat(t(this.drawBox))),e.context.barDimensions=d.barDimensions,this.emit("beforeHighlights"),J(d,s),this.emit("beforeMinorTicks"),ee(d,s),this.emit("beforeMajorTicks"),K(d,s),this.emit("beforeNumbers"),te(d,s),this.emit("beforeTitle"),ie(d,s),this.emit("beforeUnits"),re(d,s),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(r,o,a,l),e.context.save(),e.context.drawImage(e.elementClone,r,o,a,l),e.context.save(),this.emit("beforeProgressBar"),H.apply(void 0,[e.context,s].concat(t(this.drawBox))),this.emit("beforeNeedle"),oe(e.context,s),this.emit("beforeValueBox"),se.apply(void 0,[e.context,s,s.animatedValue?this.options.value:this.value].concat(t(this.drawBox))),ce(n.prototype.__proto__||Object.getPrototypeOf(n.prototype),"draw",this).call(this)}catch(e){We.verifyError(e)}return this}}],[{key:"configure",value:function(e){return e.barStrokeWidth>=e.barWidth&&(e.barStrokeWidth=ye(e.barWidth/2)),e.hasLeft=q("right",e),e.hasRight=q("left",e),e.value>e.maxValue&&(e.value=e.maxValue),e.value1&&(d=1),1!==d&&(c=r(d),isFinite(c)&&!isNaN(c)&&(d=c)),t&&t(d),s0){for(a=e.toFixed(i).toString().split("."),n=r-a[0].length;o1?(r=~i.indexOf("."),~i.indexOf("-")?"-"+[t.majorTicksInt+t.majorTicksDec+2+(r?1:0)-i.length].join("0")+i.replace("-",""):[t.majorTicksInt+t.majorTicksDec+1+(r?1:0)-i.length].join("0")+i):i}function m(e){return e*Math.PI/180}function v(e,t){return{x:-e*Math.sin(t),y:e*Math.cos(t)}}function g(e,t,i,r){var o=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],n=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,a=e.createLinearGradient(o?0:n,o?n:0,o?0:r,o?r:0);return a.addColorStop(0,t),a.addColorStop(1,i),a}function b(e,t){if(arguments.length>2&&void 0!==arguments[2]&&arguments[2])return e.restore(),!0;e.save();var i=t.borderShadowWidth;return i&&(e.shadowBlur=i,e.shadowColor=t.colorBorderShadow),!0}function p(e,t){t.needleShadow&&(e.shadowOffsetX=2,e.shadowOffsetY=2,e.shadowBlur=10,e.shadowColor=t.colorNeedleShadowDown)}function w(e,t,i){return e["font"+t+"Style"]+" "+e["font"+t+"Weight"]+" "+e["font"+t+"Size"]*i+"px "+e["font"+t]}function k(e){e.shadowOffsetX=null,e.shadowOffsetY=null,e.shadowBlur=null,e.shadowColor="",e.strokeStyle=null,e.lineWidth=0,e.save()}function y(e,t,i,r){t.valueTextShadow&&(e.shadowOffsetX=i,e.shadowOffsetY=i,e.shadowBlur=r,e.shadowColor=t.colorValueTextShadow)}function x(e,t,i,r,o,n){if(t.valueBox){k(e);var a=t.valueDec?1+t.valueDec:0,l="9".repeat(Math.max.apply(null,[String(parseInt(i)).length+a].concat(t.majorTicks.map(function(e){return String(parseInt(e,10)).length+a})))),s=t.valueText||u(i,t),d=n/200,c=n/100,f=.4*c,m=1.2*c;e.font=w(t,"Value",d),y(e,t,f,m);var v=e.measureText(t.valueText?s:"-"+u(Number(l),t)).width;k(e);var g=parseFloat(t.fontValueSize)*d+f+m,b=c*parseFloat(t.valueBoxStroke),p=2*n-2*b,x=v+10*c,T=1.1*g+f+m,S=c*t.valueBoxBorderRadius,V=(parseFloat(t.valueBoxWidth)||0)/100*p;V>x&&(x=V),x>p&&(x=p);var W=r-x/2,O=o-T/2,A=o-5.75*c;if(e.beginPath(),S?h(e,W,O,x,T,S):e.rect(W,O,x,T),b){var P=e.createRadialGradient(r,A,10*c,r,A,20*c);P.addColorStop(0,t.colorValueBoxRect),P.addColorStop(1,t.colorValueBoxRectEnd),e.strokeStyle=P,e.lineWidth=b,e.stroke()}t.colorValueBoxShadow&&(e.shadowBlur=1.2*c,e.shadowColor=t.colorValueBoxShadow),t.colorValueBoxBackground&&(e.fillStyle=t.colorValueBoxBackground,e.fill()),e.closePath(),e.restore(),y(e,t,f,m),e.fillStyle=t.colorValueText,e.textAlign="center",e.textBaseline="alphabetic",e.fillText(s,W+x/2,o+T/2-g/3),e.restore()}}function T(e){var t=e.value,i=e.minValue,r=e.maxValue,o=.01*(r-i);return{normal:tr?r:t,indented:tr?r+o:t}}function S(e,t,i,r,o){i.beginPath(),i.arc(0,0,xe(e),0,2*Oe,!0),i.lineWidth=t,i.strokeStyle=o?We.linearGradient(i,r,o,e):r,i.stroke(),i.closePath()}function V(e,t){var i=pe.pixelRatio;return e.maxRadius||(e.maxRadius=e.max-t.borderShadowWidth-t.borderOuterWidth*i-t.borderMiddleWidth*i-t.borderInnerWidth*i+(t.borderOuterWidth?.5:0)+(t.borderMiddleWidth?.5:0)+(t.borderInnerWidth?.5:0)),e.maxRadius}function W(e,t){var i=pe.pixelRatio,r=t.borderShadowWidth*i,o=e.max-r-t.borderOuterWidth*i/2,n=o-t.borderOuterWidth*i/2-t.borderMiddleWidth*i/2+.5,a=n-t.borderMiddleWidth*i/2-t.borderInnerWidth*i/2+.5,l=V(e,t),s=void 0,d=!1;e.save(),t.borderOuterWidth&&(d=We.drawShadow(e,t,d),S(o,t.borderOuterWidth*i,e,t.colorBorderOuter,t.colorBorderOuterEnd)),t.borderMiddleWidth&&(d=We.drawShadow(e,t,d),S(n,t.borderMiddleWidth*i,e,t.colorBorderMiddle,t.colorBorderMiddleEnd)),t.borderInnerWidth&&(d=We.drawShadow(e,t,d),S(a,t.borderInnerWidth*i,e,t.colorBorderInner,t.colorBorderInnerEnd)),We.drawShadow(e,t,d),e.beginPath(),e.arc(0,0,xe(l),0,2*Oe,!0),t.colorPlateEnd?(s=e.createRadialGradient(0,0,l/2,0,0,l),s.addColorStop(0,t.colorPlate),s.addColorStop(1,t.colorPlateEnd)):s=t.colorPlate,e.fillStyle=s,e.fill(),e.closePath(),e.restore()}function O(e,t){var i=e.max*(parseFloat(t.highlightsWidth)||0)/100;if(i){var r=xe(P(e,t)-i/2),o=0,n=t.highlights.length,a=(t.maxValue-t.minValue)/t.ticksAngle;for(e.save();on?o:n,n>o,o>n?i:r):a,t>0?We.roundRect(e,i,r,o,n,t):e.rect(i,r,o,n),e.fill(),e.closePath()}function G(e,t,i,r,o,n,a,l,s){e.beginPath(),e.lineWidth=t,e.strokeStyle=s?We.linearGradient(e,l,s,a,!0,o):l,i>0?We.roundRect(e,r,o,n,a,i):e.rect(r,o,n,a),e.stroke(),e.closePath()}function F(e,t,i,r,o,n){var a=pe.pixelRatio;e.save();var l=t.borderRadius*a,s=o-t.borderShadowWidth-t.borderOuterWidth*a,d=s-t.borderOuterWidth*a-t.borderMiddleWidth*a,c=d-t.borderMiddleWidth*a-t.borderInnerWidth*a,h=c-t.borderInnerWidth*a,u=n-t.borderShadowWidth-t.borderOuterWidth*a,f=u-t.borderOuterWidth*a-t.borderMiddleWidth*a,m=f-t.borderMiddleWidth*a-t.borderInnerWidth*a,v=m-t.borderInnerWidth*a,g=i-(d-s)/2,b=g-(c-d)/2,p=b-(h-c)/2,w=r-(f-u)/2,k=w-(m-f)/2,y=k-(v-m)/2,x=0,T=!1;return t.borderOuterWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderOuterWidth*a,l,i+t.borderOuterWidth*a/2-x,r+t.borderOuterWidth*a/2-x,s,u,t.colorBorderOuter,t.colorBorderOuterEnd),x+=.5*a),t.borderMiddleWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderMiddleWidth*a,l-=1+2*x,g+t.borderMiddleWidth*a/2-x,w+t.borderMiddleWidth*a/2-x,d+2*x,f+2*x,t.colorBorderMiddle,t.colorBorderMiddleEnd),x+=.5*a),t.borderInnerWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderInnerWidth*a,l-=1+2*x,b+t.borderInnerWidth*a/2-x,k+t.borderInnerWidth*a/2-x,c+2*x,m+2*x,t.colorBorderInner,t.colorBorderInnerEnd),x+=.5*a),We.drawShadow(e,t,T),L(e,l,p,y,h+2*x,v+2*x,t.colorPlate,t.colorPlateEnd),e.restore(),[p,y,h,v]}function X(e,t,i,r,o,n){var a=pe.pixelRatio,l=n>=o,s=l?.85*o:n,d=l?n:o;i=l?ye(i+(o-s)/2):i;var c=!!t.title,h=!!t.units,u=!!t.valueBox,f=void 0,m=void 0,v=void 0;l?(m=ye(.05*d),f=ye(.075*d),v=ye(.11*d),c&&(d-=f,r+=f),h&&(d-=m),u&&(d-=v)):(m=f=ye(.15*s),c&&(s-=f,r+=f),h&&(s-=m));var g=2*t.barStrokeWidth,b=t.barBeginCircle?ye(s*t.barBeginCircle/200-g/2):0,p=ye(s*t.barWidth/100-g),w=ye(d*t.barLength/100-g),k=ye((d-w)/2),y=ye(i+(l?s/2:k+b)),x=ye(r+(l?d-k-b+g/2:s/2)),T=!l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s,S=l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s;return e.barDimensions={isVertical:l,width:s,length:d,barWidth:p,barLength:w,strokeWidth:g,barMargin:k,radius:b,pixelRatio:a,barOffset:null,titleMargin:c?f:0,unitsMargin:h?m:0,get ticksLength(){return this.barLength-this.barOffset-this.strokeWidth},X:i+T,Y:r+S,x0:y+T,y0:x+S,baseX:i,baseY:r,ticksPadding:t.ticksPadding/100},e.barDimensions}function Y(e,t,i,r,o,n,a){var l=X(e,t,r,o,n,a),s=l.isVertical,d=l.width,c=l.barWidth,h=l.barLength,u=l.strokeWidth,f=l.barMargin,m=l.radius,v=l.x0,g=l.y0,b=l.X,p=l.Y,w=h;if(e.save(),e.beginPath(),t.barBeginCircle){var k=We.radians(s?270:0),y=Math.asin(c/2/m),x=Math.cos(y),T=Math.sin(y),S=v+(s?m*T:m*x-u/2),V=s?g-m*x:g+m*T,W=xe(s?V-g:S-v);e.barDimensions.barOffset=ye(W+m);var O=s?ye(v-m*T):S,A=s?V:ye(g-m*T);"progress"===i&&(h=e.barDimensions.barOffset+(h-e.barDimensions.barOffset)*(We.normalizedValue(t).normal-t.minValue)/(t.maxValue-t.minValue));var P=ye(S+h-e.barDimensions.barOffset+u/2),M=ye(V-h+e.barDimensions.barOffset-u/2);e.arc(v,g,m,k+y,k-y),s?(e.moveTo(S,A),e.lineTo(S,M),e.lineTo(O,M),e.lineTo(O,A)):(e.moveTo(S,A),e.lineTo(P,A),e.lineTo(P,V),e.lineTo(S,V))}else{var B=ye(s?b+(d-c)/2:b+f),C=ye(s?p+h+f:p+(d-c)/2);"progress"===i&&(h*=(t.value-t.minValue)/(t.maxValue-t.minValue)),s?e.rect(B,C,c,-h):e.rect(B,C,h,c)}"progress"!==i&&t.barStrokeWidth&&(e.lineWidth=u,e.strokeStyle=t.colorBarStroke,e.stroke()),"progress"!==i&&t.colorBar?(e.fillStyle=t.colorBarEnd?We.linearGradient(e,t.colorBar,t.colorBarEnd,h,s,s?p:b):t.colorBar,e.fill()):"progress"===i&&t.colorBarProgress&&(e.fillStyle=t.colorBarProgressEnd?We.linearGradient(e,t.colorBarProgress,t.colorBarProgressEnd,w,s,s?p:b):t.colorBarProgress,e.fill()),e.closePath(),e.restore(),t.barBeginCircle&&(e.barDimensions.radius+=u),e.barDimensions.barWidth+=u,e.barDimensions.barLength+=u}function U(e,t,i,r,o,n){Y(e,t,"",i,r,o,n)}function q(e,t){return t.needleSide!==e||t.tickSide!==e||t.numberSide!==e}function H(e,t,i,r,o,n){t.barProgress&&Y(e,t,"progress",i,r,o,n)}function J(e,t){var i=e.barDimensions,r=i.isVertical,o=i.width,n=i.length,a=i.barWidth,l=i.barOffset,s=i.barMargin,d=i.X,c=i.Y,h=i.ticksLength,u=i.ticksPadding,f=o*(parseFloat(t.highlightsWidth)||0)/100;if(t.highlights&&f){var m="right"!==t.tickSide,v="left"!==t.tickSide,g=0,b=t.highlights.length,p=(o-a)/2,w=t.maxValue-t.minValue,k=ye(r?d+p:d+s+l),y=f,x=r?c+n-s-l:c+p,T=ye((t.ticksWidth/100+u)*o)+(f-t.ticksWidth/100*o),S=ye(a+u*o);for(e.save();gn&&(d*=-1),e.moveTo(i-h,r),e.lineTo(i+h,r),e.lineTo(i+h,r+d),e.lineTo(i,n),e.lineTo(i-h,r+d),e.lineTo(i-h,r)):(i>o&&(d*=-1),e.moveTo(i,r-h),e.lineTo(i,r+h),e.lineTo(i+d,r+h),e.lineTo(o,r),e.lineTo(i+d,r-h),e.lineTo(i,r-h)),e.fill(),e.closePath()}function se(e,t,i,r,o,n,a){var l=(parseFloat(t.fontValueSize)||0)*n/200,s=(.11*a-l)/2;e.barDimensions.isVertical&&We.drawValueBox(e,t,i,r+n/2,o+a-l-s,n)}var de=function(){function e(e,t){var i=[],r=!0,o=!1,n=void 0;try{for(var a,l=e[Symbol.iterator]();!(r=(a=l.next()).done)&&(i.push(a.value),!t||i.length!==t);r=!0);}catch(e){o=!0,n=e}finally{try{!r&&l.return&&l.return()}finally{if(o)throw n}}return i}return function(t,i){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),ce=function e(t,i,r){null===t&&(t=Function.prototype);var o=Object.getOwnPropertyDescriptor(t,i);if(void 0===o){var n=Object.getPrototypeOf(t);return null===n?void 0:e(n,i,r)}if("value"in o)return o.value;var a=o.get;if(void 0!==a)return a.call(r)},he=function e(t,i,r,o){var n=Object.getOwnPropertyDescriptor(t,i);if(void 0===n){var a=Object.getPrototypeOf(t);null!==a&&e(a,i,r,o)}else if("value"in n&&n.writable)n.value=r;else{var l=n.set;void 0!==l&&l.call(o,r)}return r},ue=function(){function e(e,t){for(var i=0;i>>0;if(0===o)return-1;var n=+t||0;if(Math.abs(n)===1/0&&(n=0),n>=o)return-1;for(i=Math.max(n>=0?n:o-Math.abs(n),0);i>>0,r=arguments[1],o=r>>0,n=o<0?Math.max(i+o,0):Math.min(o,i),a=arguments[2],l=void 0===a?i:a>>0,s=l<0?Math.max(i+l,0):Math.min(l,i);n1?r-1:0),n=1;n1?t-1:0),r=1;r=(7-4*t)/11)return-Math.pow((11-6*t-11*e)/4,2)+Math.pow(i,2)},elastic:function(e){return 1-ve.delastic(1-e)},delastic:function(e){return Math.pow(2,10*(e-1))*Math.cos(20*Math.PI*1.5/3*e)}},ge=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"linear",i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:250,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){};if(o(this,e),this.duration=i,this.rule=t,this.draw=r,this.end=n,"function"!=typeof this.draw)throw new TypeError("Invalid animation draw callback:",r);if("function"!=typeof this.end)throw new TypeError("Invalid animation end callback:",n)}return ue(e,[{key:"animate",value:function(e,t){var i=this;this.frame&&this.cancel();var r=window.performance&&window.performance.now?window.performance.now():n("animationStartTime")||Date.now();e=e||this.draw,t=t||this.end,this.draw=e,this.end=t,this.frame=me(function(o){return a(o,e,r,ve[i.rule]||i.rule,i.duration,t,i)})}},{key:"cancel",value:function(){if(this.frame){(n("cancelAnimationFrame")||function(e){})(this.frame),this.frame=null}}},{key:"destroy",value:function(){this.cancel(),this.draw=null,this.end=null}}]),e}();ge.rules=ve;var be=function(){function t(i,r,n){o(this,t),this.options=i,this.element=r.toLowerCase(),this.type=t.toDashed(n),this.Type=e[n],this.mutationsObserved=!1,this.isObservable=!!window.MutationObserver,window.GAUGES_NO_AUTO_INIT||t.domReady(this.traverse.bind(this))}return ue(t,[{key:"isValidNode",value:function(e){return!(!e.tagName||e.tagName.toLowerCase()!==this.element||e.getAttribute("data-type")!==this.type)}},{key:"traverse",value:function(){for(var e=document.getElementsByTagName(this.element),t=0,i=e.length;t1&&void 0!==arguments[1])||arguments[1],i=e.split(/-/),r=0,o=i.length,n="";r1&&void 0!==arguments[1]?arguments[1]:0;return e=parseFloat(e),!isNaN(e)&&isFinite(e)||(e=parseFloat(t)||0),e}},{key:"mod",value:function(e,t){return(e%t+t)%t}},{key:"version",get:function(){return ke}}]),n}(fe);void 0!==e&&(e.BaseGauge=Se,e.gauges=(window.document||{}).gauges=Te);var Ve=/{([_a-zA-Z]+[_a-zA-Z0-9]*)}/g,We={roundRect:h,padValue:u,formatMajorTickNumber:f,radians:m,radialPoint:v,linearGradient:g,drawNeedleShadow:p,drawValueBox:x,verifyError:s,prepareTicks:c,drawShadow:b,font:w,normalizedValue:T,formatContext:d},Oe=Math.PI,Ae=Oe/2,Pe=Object.assign({},we,{ticksAngle:270,startAngle:45,colorNeedleCircleOuter:"#f0f0f0",colorNeedleCircleOuterEnd:"#ccc",colorNeedleCircleInner:"#e8e8e8",colorNeedleCircleInnerEnd:"#f5f5f5",needleCircleSize:10,needleCircleInner:!0,needleCircleOuter:!0,needleStart:20,animationTarget:"needle",useMinPath:!1,barWidth:0,barStartPosition:"left"}),Me=function(e){function t(e){return o(this,t),e=Object.assign({},Pe,e||{}),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,t.configure(e)))}return r(t,e),ue(t,[{key:"draw",value:function(){try{var e=this.canvas,i=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],r=i[0],o=i[1],n=i[2],a=i[3],l=this.options;if("needle"===l.animationTarget){if(!e.elementClone.initialized){var s=e.contextClone;s.clearRect(r,o,n,a),s.save(),this.emit("beforePlate"),W(s,l),this.emit("beforeHighlights"),O(s,l),this.emit("beforeMinorTicks"),A(s,l),this.emit("beforeMajorTicks"),M(s,l),this.emit("beforeNumbers"),j(s,l),this.emit("beforeTitle"),N(s,l),this.emit("beforeUnits"),E(s,l),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(r,o,n,a),e.context.drawImage(e.elementClone,r,o,n,a),e.context.save(),this.emit("beforeProgressBar"),D(e.context,l),this.emit("beforeValueBox"),R(e.context,l,z(this)),this.emit("beforeNeedle"),_(e.context,l)}else{var d=-We.radians((l.value-l.minValue)/(l.maxValue-l.minValue)*l.ticksAngle);if(e.context.clearRect(r,o,n,a),e.context.save(),this.emit("beforePlate"),W(e.context,l),e.context.rotate(d),this.emit("beforeHighlights"),O(e.context,l),this.emit("beforeMinorTicks"),A(e.context,l),this.emit("beforeMajorTicks"),M(e.context,l),this.emit("beforeNumbers"),j(e.context,l),this.emit("beforeProgressBar"),D(e.context,l),e.context.rotate(-d),e.context.save(),!e.elementClone.initialized){var c=e.contextClone;c.clearRect(r,o,n,a),c.save(),this.emit("beforeTitle"),N(c,l),this.emit("beforeUnits"),E(c,l),this.emit("beforeNeedle"),_(c,l),e.elementClone.initialized=!0}e.context.drawImage(e.elementClone,r,o,n,a)}this.emit("beforeValueBox"),R(e.context,l,z(this)),ce(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"draw",this).call(this)}catch(e){We.verifyError(e)}return this}},{key:"value",set:function(e){e=Se.ensureValue(e,this.options.minValue),this.options.animation&&360===this.options.ticksAngle&&this.options.useMinPath&&(this._value=e,e=this.options.value+((e-this.options.value)%360+540)%360-180),he(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"value",e,this)},get:function(){return ce(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"value",this)}}],[{key:"configure",value:function(e){return e.barWidth>50&&(e.barWidth=50),isNaN(e.startAngle)&&(e.startAngle=45),isNaN(e.ticksAngle)&&(e.ticksAngle=270),e.ticksAngle>360&&(e.ticksAngle=360),e.ticksAngle<0&&(e.ticksAngle=0),e.startAngle<0&&(e.startAngle=0),e.startAngle>360&&(e.startAngle=360),e}}]),t}(Se);void 0!==e&&(e.RadialGauge=Me),Se.initialize("RadialGauge",Pe);var Be=Object.assign({},we,{borderRadius:0,barBeginCircle:30,colorBarEnd:"",colorBarProgressEnd:"",needleWidth:6,tickSide:"both",needleSide:"both",numberSide:"both",ticksWidth:10,ticksWidthMinor:5,ticksPadding:5,barLength:85,fontTitleSize:26,highlightsWidth:10}),Ce=function(e){function n(e){return o(this,n),e=Object.assign({},Be,e||{}),i(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n.configure(e)))}return r(n,e),ue(n,[{key:"draw",value:function(){try{var e=this.canvas,i=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],r=i[0],o=i[1],a=i[2],l=i[3],s=this.options;if(!e.elementClone.initialized){var d=e.contextClone;d.clearRect(r,o,a,l),d.save(),this.emit("beforePlate"),this.drawBox=F(d,s,r,o,a,l),this.emit("beforeBar"),U.apply(void 0,[d,s].concat(t(this.drawBox))),e.context.barDimensions=d.barDimensions,this.emit("beforeHighlights"),J(d,s),this.emit("beforeMinorTicks"),ee(d,s),this.emit("beforeMajorTicks"),K(d,s),this.emit("beforeNumbers"),te(d,s),this.emit("beforeTitle"),ie(d,s),this.emit("beforeUnits"),re(d,s),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(r,o,a,l),e.context.drawImage(e.elementClone,r,o,a,l),this.emit("beforeProgressBar"),H.apply(void 0,[e.context,s].concat(t(this.drawBox))),this.emit("beforeNeedle"),oe(e.context,s),this.emit("beforeValueBox"),se.apply(void 0,[e.context,s,s.animatedValue?this.options.value:this.value].concat(t(this.drawBox))),ce(n.prototype.__proto__||Object.getPrototypeOf(n.prototype),"draw",this).call(this)}catch(e){We.verifyError(e)}return this}}],[{key:"configure",value:function(e){return e.barStrokeWidth>=e.barWidth&&(e.barStrokeWidth=ye(e.barWidth/2)),e.hasLeft=q("right",e),e.hasRight=q("left",e),e.value>e.maxValue&&(e.value=e.maxValue),e.value 0) { drawProgress(context, options, progress); @@ -443,10 +439,8 @@ export class CanvasDigitalGauge extends BaseGauge { // clear the canvas canvas.context.clearRect(x, y, w, h); - canvas.context.save(); canvas.context.drawImage(this.elementProgressClone, x, y, w, h); - canvas.context.save(); // @ts-ignore super.draw(); @@ -754,6 +748,7 @@ function drawDigitalTitle(context: DigitalGaugeCanvasRenderingContext2D, options context.font = Drawings.font(options, 'Title', fontSizeFactor); context.lineWidth = 0; drawText(context, options, 'Title', options.title.toUpperCase(), textX, textY); + context.restore(); } function drawDigitalLabel(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions) { @@ -772,6 +767,7 @@ function drawDigitalLabel(context: DigitalGaugeCanvasRenderingContext2D, options context.font = Drawings.font(options, 'Label', fontSizeFactor); context.lineWidth = 0; drawText(context, options, 'Label', options.label, textX, textY); + context.restore(); } function drawDigitalMinMax(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions) { @@ -789,6 +785,7 @@ function drawDigitalMinMax(context: DigitalGaugeCanvasRenderingContext2D, option context.lineWidth = 0; drawText(context, options, 'MinMax', options.minValue + '', minX, minY); drawText(context, options, 'MinMax', options.maxValue + '', maxX, maxY); + context.restore(); } function drawDigitalValue(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions, value: any) { @@ -811,6 +808,7 @@ function drawDigitalValue(context: DigitalGaugeCanvasRenderingContext2D, options context.font = Drawings.font(options, 'Value', fontSizeFactor); context.lineWidth = 0; drawText(context, options, 'Value', text, textX, textY); + context.restore(); } function getProgressColor(progress: number, colorsRange: DigitalGaugeColorRange[]): string { @@ -944,6 +942,7 @@ function drawTickBar(context: DigitalGaugeCanvasRenderingContext2D, tickValues: function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions, progress: number) { let neonColor; + context.save(); if (options.neonGlowBrightness) { context.currentColor = neonColor = getProgressColor(progress, options.neonColorsRange); } else { @@ -1019,4 +1018,5 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, true, options.colorTicks, options.tickWidth); } + context.restore(); } From e84fbdf6549ce0f63c9ee5d1bb71a8b98ad4af50 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sun, 24 Oct 2021 23:15:59 +0300 Subject: [PATCH 124/303] Lwm2m controller swagger --- .../controller/ControllerConstants.java | 45 +++++++++++++++++++ .../server/controller/Lwm2mController.java | 33 ++++++++++++-- .../data/lwm2m/ServerSecurityConfig.java | 21 +++++++-- .../thingsboard/rest/client/RestClient.java | 1 - 4 files changed, 92 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index c63f6178c7..d9b454d1b4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -142,6 +142,51 @@ public class ControllerConstants { protected static final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; protected static final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; + protected static final String IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION = "A Boolean value representing the Server SecurityInfo for future Bootstrap client mode settings. Values: 'true' for Bootstrap Server; 'false' for Lwm2m Server. "; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION = + " {\n\"class org.thingsboard.server.common.data.Device\":{\n" + + " \"id\": \"null\",\n" + + " \"createdTime\":0,\n" + + " \"additionalInfo\":\"null\",\n" + + " \"tenantId\":\"null\",\n" + + " \"customerId\":\"null\",\n" + + " \"name\":\"LwRpk00000000\",\n" + + " \"type\":\"lwm2mProfileRpk\",\n" + + " \"label\":\"null\",\"" + + " \"deviceProfileId\":\"null\",\n" + + " \"deviceData\":\"null\",\n" + + " \"firmwareId\":\"null\",\n" + + " \"softwareId\":\"null\"\n" + + " },\n" + + " \"class org.thingsboard.server.common.data.security.DeviceCredentials\":{\n" + + " \"class_DeviceCredentials1\":{\n" + + " \"id\":\"null\",\n" + + " \"createdTime\":0,\n" + + " \"deviceId\":\"null|',\n" + + " \"credentialsType\":\"LWM2M_CREDENTIALS\",\n" + + " \"credentialsId\":\"LwRpk00000000\",\n" + + " \"credentialsValue\":{\n" + + " \"client\":{\n" + + " \"endpoint\":\"LwRpk00000000\",\n" + + " \"securityConfigClientMode\":\"RPK\",\n" + + " \"key\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\"\n" + + " },\n" + + " \"bootstrap\":{\n" + + " \"bootstrapServer\":{\n" + + " \"securityMode\":\"RPK\",\n" + + " \"clientPublicKeyOrId\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\",\n" + + " \"clientSecretKey\":\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\"" + + " },\n" + + " \"lwm2mServer\":{\n" + + " \"securityMode\":\"RPK\",\n" + + " \"clientPublicKeyOrId\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\",\n" + + " \"clientSecretKey\":\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + "Provides a hint about the data type of the entity field that is defined in the filter key. " + "The value type impacts the list of possible operations that you may use in the corresponding predicate. For example, you may use 'STARTS_WITH' or 'END_WITH', but you can't use 'GREATER_OR_EQUAL' for string values." + diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 64537d9f5f..1117f78dc5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -16,6 +16,8 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -35,16 +37,28 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.Map; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + @Slf4j @RestController @TbCoreComponent @RequestMapping("/api") public class Lwm2mController extends BaseController { + public static final String IS_BOOTSTRAP_SERVER = "isBootstrapServer"; + + @ApiOperation(value = "Get Lwm2m Bootstrap SecurityInfo (getLwm2mBootstrapSecurityInfo)", + notes = "Get the Lwm2m Bootstrap SecurityInfo object (of the current server) based on the provided isBootstrapServer parameter. If isBootstrapServer == true, get the parameters of the current Bootstrap Server. If isBootstrapServer == false, get the parameters of the current Lwm2m Server. Used for client settings when starting the client in Bootstrap mode. " + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) @ResponseBody - public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("isBootstrapServer") boolean bootstrapServer) throws ThingsboardException { + public ServerSecurityConfig getLwm2mBootstrapSecurityInfo( + @ApiParam(value = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION) + @PathVariable(IS_BOOTSTRAP_SERVER) boolean bootstrapServer) throws ThingsboardException { try { return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(bootstrapServer); } catch (Exception e) { @@ -52,13 +66,26 @@ public class Lwm2mController extends BaseController { } } + @ApiOperation(value = "Create Device (saveDevice) with credentials ", + notes = "\nCreate new Device with credentials (example with security mode: RPK\n" + + "\nRequestBody is the Map, Object>:\n" + + "\nThe first param of this map: Device\n"+ + "\n-- key1 = \"class org.thingsboard.server.common.data.Device\" - value1 = \"new Device()\"\n" + + "\nThe second param of this map: Device credentials\n" + + "\n-- key2 = \"class org.thingsboard.server.common.data.security.DeviceCredentials\" - value2 = \"new DeviceCredentials()\"\n" + + "\n- Example of the RequestBody with security mode: RPK:\n" + + "\n- " + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION + "\n" + + "\nWhen creating new device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address).\n" + + "\nAfter creating new device Device DeviceCredentials is added to new Device." + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/device-credentials", method = RequestMethod.POST) @ResponseBody - public Device saveDeviceWithCredentials(@RequestBody (required=false) Map, Object> deviceWithDeviceCredentials) throws ThingsboardException { + public Device saveDeviceWithCredentials(@ApiParam(value = DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION) + @RequestBody(required = false) Map, Object> deviceWithDeviceCredentials) throws ThingsboardException { ObjectMapper mapper = new ObjectMapper(); Device device = checkNotNull(mapper.convertValue(deviceWithDeviceCredentials.get(Device.class), Device.class)); - DeviceCredentials credentials = checkNotNull(mapper.convertValue( deviceWithDeviceCredentials.get(DeviceCredentials.class), DeviceCredentials.class)); + DeviceCredentials credentials = checkNotNull(mapper.convertValue(deviceWithDeviceCredentials.get(DeviceCredentials.class), DeviceCredentials.class)); try { device.setTenantId(getCurrentUser().getTenantId()); checkEntity(device.getId(), device, Resource.DEVICE); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java index 8220702ec8..0fe6be34eb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java @@ -15,17 +15,30 @@ */ package org.thingsboard.server.common.data.lwm2m; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; +@ApiModel @Data public class ServerSecurityConfig { + @ApiModelProperty(position = 1, value = "Is Bootstrap Server.", example = "true", readOnly = true) + boolean bootstrapServerIs = true; + @ApiModelProperty(position = 2, value = "Host No Security.", example = "0.0.0.0", readOnly = true) String host; - String securityHost; + @ApiModelProperty(position = 3, value = "Port No Security.", example = "5687", readOnly = true) Integer port; + @ApiModelProperty(position = 4, value = "Host Security.", example = "0.0.0.0", readOnly = true) + String securityHost; + @ApiModelProperty(position = 5, value = "Port Security.", example = "5688", readOnly = true) Integer securityPort; - String serverPublicKey; - boolean bootstrapServerIs = true; - Integer clientHoldOffTime = 1; + @ApiModelProperty(position = 5, value = "Server short Id.", example = "111", readOnly = true) Integer serverId = 111; + @ApiModelProperty(position = 7, value = "Client Hold Off Time.", example = "1", readOnly = true) + Integer clientHoldOffTime = 1; + @ApiModelProperty(position = 8, value = "Server Public Key (formar base64).", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + + "+44sgk3c8g0LotfMpLlZJPhPwJ6ipXV+O1r7IZUjBs3LNA==", readOnly = true) + String serverPublicKey; + @ApiModelProperty(position = 9, value = "Bootstrap Server Account Timeout.", example = "0", readOnly = true) Integer bootstrapServerAccountTimeout = 0; } diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 30dc57eeb7..376b08baab 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -1134,7 +1134,6 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { Map, Object> deviceCredentials = new ConcurrentHashMap<>(); deviceCredentials.put(Device.class, device); deviceCredentials.put(DeviceCredentials.class, credentials); -// return restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class).getBody(); ResponseEntity deviceOpt = restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class); return Optional.ofNullable(deviceOpt.getBody()); } catch (HttpClientErrorException exception) { From a91b458a360fd761f11e14e46f4798b77d71a50e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 25 Oct 2021 09:15:26 +0300 Subject: [PATCH 125/303] Improve help popup component --- ui-ngx/src/app/shared/components/help-popup.component.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/shared/components/help-popup.component.html b/ui-ngx/src/app/shared/components/help-popup.component.html index a401459198..519ff4f58b 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.html +++ b/ui-ngx/src/app/shared/components/help-popup.component.html @@ -15,9 +15,8 @@ limitations under the License. --> -
    +
    +
    +
    diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.html b/ui-ngx/src/app/shared/components/protobuf-content.component.html new file mode 100644 index 0000000000..43765c66d7 --- /dev/null +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.html @@ -0,0 +1,30 @@ +
    +
    + + + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.scss b/ui-ngx/src/app/shared/components/protobuf-content.component.scss new file mode 100644 index 0000000000..70d3e3267d --- /dev/null +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.scss @@ -0,0 +1,43 @@ +:host { + position: relative; + + .fill-height { + height: 100%; + } +} + +.tb-protobuf-content-toolbar { + button.mat-button, button.mat-icon-button, button.mat-icon-button.tb-mat-32 { + align-items: center; + vertical-align: middle; + min-width: 32px; + min-height: 15px; + padding: 4px; + margin: 0; + font-size: .8rem; + line-height: 15px; + color: #7b7b7b; + background: rgba(220, 220, 220, .35); + &:not(:last-child) { + margin-right: 4px; + } + } +} + +.tb-protobuf-content-panel { + height: 100%; + margin-left: 15px; + border: 1px solid #c0c0c0; + overflow: auto; + resize: vertical; + + #tb-protobuf-input { + width: 100%; + min-width: 200px; + min-height: 100px; + + &:not(.fill-height) { + min-height: 200px; + } + } +} diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.ts b/ui-ngx/src/app/shared/components/protobuf-content.component.ts new file mode 100644 index 0000000000..e640c05331 --- /dev/null +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.ts @@ -0,0 +1,221 @@ +import { + Component, + ElementRef, + forwardRef, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; +import { Ace } from 'ace-builds'; +import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; +import { ResizeObserver } from '@juggle/resize-observer'; +import { guid } from '@core/utils'; +import { ContentType } from '@shared/models/constants'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { getAce } from '@shared/models/ace/ace.models'; +import { beautifyJs } from '@shared/models/beautify.models'; +import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions'; + +@Component({ + selector: 'tb-protobuf-content', + templateUrl: './protobuf-content.component.html', + styleUrls: ['./protobuf-content.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ProtobufContentComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => ProtobufContentComponent), + multi: true, + } + ] +}) +export class ProtobufContentComponent implements OnInit, ControlValueAccessor, Validator, OnChanges, OnDestroy { + + @ViewChild('protobufEditor', {static: true}) + protobufEditorElmRef: ElementRef; + + private protobufEditor: Ace.Editor; + private editorsResizeCaf: CancelAnimationFrame; + private editorResize$: ResizeObserver; + private ignoreChange = false; + + toastTargetId = `protobufContentEditor-${guid()}`; + + @Input() label: string; + + contentType: ContentType = ContentType.TEXT; + + @Input() disabled: boolean; + + @Input() fillHeight: boolean; + + @Input() editorStyle: {[klass: string]: any}; + + @Input() tbPlaceholder: string; + + private readonlyValue: boolean; + get readonly(): boolean { + return this.readonlyValue; + } + @Input() + set readonly(value: boolean) { + this.readonlyValue = coerceBooleanProperty(value); + } + + fullscreen = false; + + contentBody: string; + + contentValid: boolean; + + errorShowed = false; + + private propagateChange = null; + + constructor(public elementRef: ElementRef, + protected store: Store, + private raf: RafService) { + } + + ngOnInit(): void { + const editorElement = this.protobufEditorElmRef.nativeElement; + let mode = 'protobuf'; + let editorOptions: Partial = { + mode: `ace/mode/${mode}`, + showGutter: true, + showPrintMargin: false, + readOnly: this.disabled || this.readonly, + }; + + const advancedOptions = { + enableSnippets: true, + enableBasicAutocompletion: true, + enableLiveAutocompletion: true, + autoScrollEditorIntoView: true + }; + + editorOptions = {...editorOptions, ...advancedOptions}; + getAce().subscribe( + (ace) => { + this.protobufEditor = ace.edit(editorElement, editorOptions); + this.protobufEditor.session.setUseWrapMode(true); + this.protobufEditor.setValue(this.contentBody ? this.contentBody : '', -1); + this.protobufEditor.setReadOnly(this.disabled || this.readonly); + this.protobufEditor.on('change', () => { + if (!this.ignoreChange) { + this.updateView(); + } + }); + this.editorResize$ = new ResizeObserver(() => { + this.onAceEditorResize(); + }); + this.editorResize$.observe(editorElement); + } + ); + } + + ngOnDestroy(): void { + if (this.editorResize$) { + this.editorResize$.disconnect(); + } + } + + private onAceEditorResize() { + if (this.editorsResizeCaf) { + this.editorsResizeCaf(); + this.editorsResizeCaf = null; + } + this.editorsResizeCaf = this.raf.raf(() => { + this.protobufEditor.resize(); + this.protobufEditor.renderer.updateFull(); + }); + } + + ngOnChanges(changes: SimpleChanges): void { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue) { + if (propName === 'contentType') { + if (this.protobufEditor) { + let mode = 'protobuf'; + this.protobufEditor.session.setMode(`ace/mode/${mode}`); + } + } + } + } + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.protobufEditor) { + this.protobufEditor.setReadOnly(this.disabled || this.readonly); + } + } + + public validate(c: FormControl) { + return (this.contentValid) ? null : { + contentBody: { + valid: false, + }, + }; + } + + writeValue(value: string): void { + this.contentBody = value; + this.contentValid = true; + if (this.protobufEditor) { + this.ignoreChange = true; + this.protobufEditor.setValue(this.contentBody ? this.contentBody : '', -1); + this.ignoreChange = false; + } + } + + updateView() { + const editorValue = this.protobufEditor.getValue(); + if (this.contentBody !== editorValue) { + this.contentBody = editorValue; + this.propagateChange(this.contentBody); + } + } + + beautifyJSON() { + beautifyJs(this.contentBody, {indent_size: 4, wrap_line_length: 60}).subscribe( + (res) => { + this.protobufEditor.setValue(res ? res : '', -1); + this.updateView(); + } + ); + } + + minifyJSON() { + const res = JSON.stringify(this.contentBody); + this.protobufEditor.setValue(res ? res : '', -1); + this.updateView(); + } + + onFullscreen() { + if (this.protobufEditor) { + setTimeout(() => { + this.protobufEditor.resize(); + }, 0); + } + } + +} diff --git a/ui-ngx/src/app/shared/models/ace/ace.models.ts b/ui-ngx/src/app/shared/models/ace/ace.models.ts index f87275e679..c9136b8e79 100644 --- a/ui-ngx/src/app/shared/models/ace/ace.models.ts +++ b/ui-ngx/src/app/shared/models/ace/ace.models.ts @@ -36,6 +36,7 @@ export function loadAceDependencies(): Observable { aceObservables.push(from(import('ace-builds/src-noconflict/mode-text'))); aceObservables.push(from(import('ace-builds/src-noconflict/mode-markdown'))); aceObservables.push(from(import('ace-builds/src-noconflict/mode-html'))); + aceObservables.push(from(import('ace-builds/src-noconflict/mode-protobuf'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/java'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/css'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/json'))); diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 2b1de653ec..90b80393dd 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -155,6 +155,7 @@ import { MarkedOptionsService } from '@shared/components/marked-options.service' import { TbPopoverService } from '@shared/components/popover.service'; import { HELP_MARKDOWN_COMPONENT_TOKEN, SHARED_MODULE_TOKEN } from '@shared/components/tokens'; import { TbMarkdownComponent } from '@shared/components/markdown.component'; +import { ProtobufContentComponent } from './components/protobuf-content.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -268,7 +269,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) OtaPackageAutocompleteComponent, WidgetsBundleSearchComponent, CopyButtonComponent, - TogglePasswordComponent + TogglePasswordComponent, + ProtobufContentComponent ], imports: [ CommonModule, @@ -458,7 +460,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) OtaPackageAutocompleteComponent, WidgetsBundleSearchComponent, CopyButtonComponent, - TogglePasswordComponent + TogglePasswordComponent, + ProtobufContentComponent ] }) export class SharedModule { } From 5f6b1d1ab32036470dc63e465242a2ac41a3a032 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 26 Oct 2021 12:59:05 +0300 Subject: [PATCH 140/303] MQTT backward compatibility adaptor: init commit --- .../ProtoTransportPayloadConfiguration.java | 2 + .../transport/mqtt/MqttTransportHandler.java | 16 +- .../BackwardCompatibilityAdaptor.java | 139 ++++++++++++++++++ .../mqtt/adaptors/JsonMqttAdaptor.java | 8 +- .../mqtt/adaptors/MqttTransportAdaptor.java | 18 ++- .../mqtt/adaptors/ProtoMqttAdaptor.java | 8 +- .../mqtt/session/DeviceSessionCtx.java | 13 +- ...ile-transport-configuration.component.html | 6 + ...ofile-transport-configuration.component.ts | 8 +- ui-ngx/src/app/shared/models/device.models.ts | 6 +- .../assets/locale/locale.constant-en_US.json | 2 + 11 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/ProtoTransportPayloadConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/ProtoTransportPayloadConfiguration.java index d3836a35a0..1e45ff3ba6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/ProtoTransportPayloadConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/ProtoTransportPayloadConfiguration.java @@ -54,6 +54,8 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC private String deviceRpcRequestProtoSchema; private String deviceRpcResponseProtoSchema; + private boolean enableCompatibilityWithOtherPayloadFormats; + @Override public TransportPayloadType getTransportPayloadType() { return TransportPayloadType.PROTOBUF; diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 35e6e8c508..3d04ecfdc9 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -967,6 +967,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement log.trace("[{}] Received get attributes response", sessionId); String topicBase; MqttTransportAdaptor adaptor; + boolean useBackupAdaptorByDefault = false; switch (attrReqTopicType) { case V2: adaptor = deviceSessionCtx.getPayloadAdaptor(); @@ -983,10 +984,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement default: adaptor = deviceSessionCtx.getPayloadAdaptor(); topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_TOPIC_PREFIX; + useBackupAdaptorByDefault = true; break; } try { - adaptor.convertToPublish(deviceSessionCtx, response, topicBase).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); + adaptor.convertToPublish(deviceSessionCtx, response, topicBase, useBackupAdaptorByDefault).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); } @@ -998,6 +1000,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement log.info("[{}] : attrSubTopicType: {}", notification.toString(), attrSubTopicType); String topic; MqttTransportAdaptor adaptor; + boolean useBackupAdaptorByDefault = false; switch (attrSubTopicType) { case V2: adaptor = deviceSessionCtx.getPayloadAdaptor(); @@ -1014,10 +1017,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement default: adaptor = deviceSessionCtx.getPayloadAdaptor(); topic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC; + useBackupAdaptorByDefault = true; break; } try { - adaptor.convertToPublish(deviceSessionCtx, notification, topic).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); + adaptor.convertToPublish(deviceSessionCtx, notification, topic, useBackupAdaptorByDefault).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { log.trace("[{}] Failed to convert device attributes update to MQTT msg", sessionId, e); } @@ -1034,6 +1038,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement log.info("[{}] Received RPC command to device", sessionId); String baseTopic; MqttTransportAdaptor adaptor; + boolean useBackupAdaptorByDefault = false; switch (rpcSubTopicType) { case V2: adaptor = deviceSessionCtx.getPayloadAdaptor(); @@ -1050,10 +1055,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement default: adaptor = deviceSessionCtx.getPayloadAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_TOPIC; + useBackupAdaptorByDefault = true; break; } try { - adaptor.convertToPublish(deviceSessionCtx, rpcRequest, baseTopic).ifPresent(payload -> { + adaptor.convertToPublish(deviceSessionCtx, rpcRequest, baseTopic, useBackupAdaptorByDefault).ifPresent(payload -> { int msgId = ((MqttPublishMessage) payload).variableHeader().packetId(); if (isAckExpected(payload)) { rpcAwaitingAck.put(msgId, rpcRequest); @@ -1090,6 +1096,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement log.trace("[{}] Received RPC response from server", sessionId); String baseTopic; MqttTransportAdaptor adaptor; + boolean useBackupAdaptorByDefault = false; switch (toServerRpcSubTopicType) { case V2: adaptor = deviceSessionCtx.getPayloadAdaptor(); @@ -1106,10 +1113,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement default: adaptor = deviceSessionCtx.getPayloadAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_TOPIC; + useBackupAdaptorByDefault = true; break; } try { - adaptor.convertToPublish(deviceSessionCtx, rpcResponse, baseTopic).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); + adaptor.convertToPublish(deviceSessionCtx, rpcResponse, baseTopic, useBackupAdaptorByDefault).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { log.trace("[{}] Failed to convert device RPC command to MQTT msg", sessionId, e); } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java new file mode 100644 index 0000000000..4b3a3e25b5 --- /dev/null +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java @@ -0,0 +1,139 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.adaptors; + +import io.netty.handler.codec.mqtt.MqttMessage; +import io.netty.handler.codec.mqtt.MqttPublishMessage; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.ota.OtaPackageType; +import org.thingsboard.server.common.transport.adaptor.AdaptorException; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionContext; + +import java.util.Optional; + +@Data +@AllArgsConstructor +@Slf4j +public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { + + private static final String BACKWARD_COMPATIBILITY_ENABLED = "Other payload formats compatibility enabled! Trying to convert "; + + private MqttTransportAdaptor main; + private MqttTransportAdaptor backup; + + @Override + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { + try { + return main.convertToPostTelemetry(ctx, inbound); + } catch (AdaptorException e) { + log.trace(BACKWARD_COMPATIBILITY_ENABLED + "post telemetry request msg using {} ...", backup.getClass().getSimpleName()); + return backup.convertToPostTelemetry(ctx, inbound); + } + } + + @Override + public TransportProtos.PostAttributeMsg convertToPostAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { + try { + return main.convertToPostAttributes(ctx, inbound); + } catch (AdaptorException e) { + log.trace(BACKWARD_COMPATIBILITY_ENABLED + "post attributes request msg using {} ...", backup.getClass().getSimpleName()); + return backup.convertToPostAttributes(ctx, inbound); + } + } + + @Override + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { + try { + return main.convertToGetAttributes(ctx, inbound, topicBase); + } catch (AdaptorException e) { + log.trace(BACKWARD_COMPATIBILITY_ENABLED + "get attributes request msg using {} ...", backup.getClass().getSimpleName()); + return backup.convertToGetAttributes(ctx, inbound, topicBase); + } + } + + @Override + public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(MqttDeviceAwareSessionContext ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException { + try { + return main.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); + } catch (AdaptorException e) { + log.trace(BACKWARD_COMPATIBILITY_ENABLED + "to device rpc response msg using {} ...", backup.getClass().getSimpleName()); + return backup.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); + } + } + + @Override + public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(MqttDeviceAwareSessionContext ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException { + try { + return main.convertToServerRpcRequest(ctx, mqttMsg, topicBase); + } catch (AdaptorException e) { + log.trace(BACKWARD_COMPATIBILITY_ENABLED + "to server rpc request msg using {} ...", backup.getClass().getSimpleName()); + return backup.convertToServerRpcRequest(ctx, mqttMsg, topicBase); + } + } + + @Override + public TransportProtos.ClaimDeviceMsg convertToClaimDevice(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { + try { + return main.convertToClaimDevice(ctx, inbound); + } catch (AdaptorException e) { + log.trace(BACKWARD_COMPATIBILITY_ENABLED + "claim device request msg using {} ...", backup.getClass().getSimpleName()); + return backup.convertToClaimDevice(ctx, inbound); + } + } + + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { + return useBackupAdaptorByDefault ? backup.convertToPublish(ctx, responseMsg, topicBase, false) : main.convertToPublish(ctx, responseMsg, topicBase, false); + } + + @Override + public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { + return main.convertToGatewayPublish(ctx, deviceName, responseMsg); + } + + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic, boolean useBackupAdaptorByDefault) throws AdaptorException { + return useBackupAdaptorByDefault ? backup.convertToPublish(ctx, notificationMsg, topic, false) : main.convertToPublish(ctx, notificationMsg, topic, false); + } + + @Override + public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException { + return main.convertToGatewayPublish(ctx, deviceName, notificationMsg); + } + + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { + return useBackupAdaptorByDefault ? backup.convertToPublish(ctx, rpcRequest, topicBase, false) : main.convertToPublish(ctx, rpcRequest, topicBase, false); + } + + @Override + public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException { + return main.convertToGatewayPublish(ctx, deviceName, rpcRequest); + } + + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { + return useBackupAdaptorByDefault ? backup.convertToPublish(ctx, rpcResponse, topicBase, false) : main.convertToPublish(ctx, rpcResponse, topicBase, false); + } + + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException { + return main.convertToPublish(ctx, firmwareChunk, requestId, chunk, firmwareType); + } +} diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index dc2b74a8ea..68d80538c1 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -117,7 +117,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { return processConvertFromAttributeResponseMsg(ctx, responseMsg, topicBase); } @@ -127,7 +127,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic, boolean useBackupAdaptorByDefault) { return Optional.of(createMqttPublishMsg(ctx, topic, JsonConverter.toJson(notificationMsg))); } @@ -138,7 +138,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase, boolean useBackupAdaptorByDefault) { return Optional.of(createMqttPublishMsg(ctx, topicBase + rpcRequest.getRequestId(), JsonConverter.toJson(rpcRequest, false))); } @@ -148,7 +148,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase, boolean useBackupAdaptorByDefault) { return Optional.of(createMqttPublishMsg(ctx, topicBase + rpcResponse.getRequestId(), JsonConverter.toJson(rpcResponse))); } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java index 53ef439eda..f030dd9fca 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java @@ -60,23 +60,29 @@ public interface MqttTransportAdaptor { ClaimDeviceMsg convertToClaimDevice(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException; + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException; Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, GetAttributeResponseMsg responseMsg) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException; + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic, boolean useBackupAdaptorByDefault) throws AdaptorException; Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException; + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException; Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException; + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException; - ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; + default ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { + // method is never used in BackwardCompatibilityAdaptor + return null; + } - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException; + default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException { + // method is never used in BackwardCompatibilityAdaptor + return Optional.empty(); + } Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException; diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java index 4fa47b367d..7f9b326f9d 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java @@ -135,7 +135,7 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { if (!StringUtils.isEmpty(responseMsg.getError())) { throw new AdaptorException(responseMsg.getError()); } else { @@ -148,7 +148,7 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx; DynamicMessage.Builder rpcRequestDynamicMessageBuilder = deviceSessionCtx.getRpcRequestDynamicMessageBuilder(); if (rpcRequestDynamicMessageBuilder == null) { @@ -159,12 +159,12 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase, boolean useBackupAdaptorByDefault) { return Optional.of(createMqttPublishMsg(ctx, topicBase + rpcResponse.getRequestId(), rpcResponse.toByteArray())); } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic, boolean useBackupAdaptorByDefault) { return Optional.of(createMqttPublishMsg(ctx, topic, notificationMsg.toByteArray())); } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java index ab11d859b8..cc65da1008 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.mqtt.MqttTransportContext; +import org.thingsboard.server.transport.mqtt.adaptors.BackwardCompatibilityAdaptor; import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; import org.thingsboard.server.transport.mqtt.util.MqttTopicFilter; import org.thingsboard.server.transport.mqtt.util.MqttTopicFilterFactory; @@ -76,6 +77,7 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { private volatile MqttTopicFilter telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter(); private volatile MqttTopicFilter attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter(); private volatile TransportPayloadType payloadType = TransportPayloadType.JSON; + private volatile boolean payloadFormatsCompatipilityEnabled; private volatile Descriptors.Descriptor attributesDynamicMessageDescriptor; private volatile Descriptors.Descriptor telemetryDynamicMessageDescriptor; private volatile Descriptors.Descriptor rpcResponseDynamicMessageDescriptor; @@ -103,7 +105,15 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { } public MqttTransportAdaptor getPayloadAdaptor() { - return payloadType.equals(TransportPayloadType.JSON) ? context.getJsonMqttAdaptor() : context.getProtoMqttAdaptor(); + if (payloadType.equals(TransportPayloadType.JSON)) { + return context.getJsonMqttAdaptor(); + } else { + if (payloadFormatsCompatipilityEnabled) { + return new BackwardCompatibilityAdaptor(context.getProtoMqttAdaptor(), context.getJsonMqttAdaptor()); + } else { + return context.getProtoMqttAdaptor(); + } + } } public boolean isJsonPayloadType() { @@ -162,6 +172,7 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { attributesDynamicMessageDescriptor = protoTransportPayloadConfig.getAttributesDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceAttributesProtoSchema()); rpcResponseDynamicMessageDescriptor = protoTransportPayloadConfig.getRpcResponseDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceRpcResponseProtoSchema()); rpcRequestDynamicMessageBuilder = protoTransportPayloadConfig.getRpcRequestDynamicMessageBuilder(protoTransportPayloadConfig.getDeviceRpcRequestProtoSchema()); + payloadFormatsCompatipilityEnabled = protoTransportPayloadConfig.isEnableCompatibilityWithOtherPayloadFormats(); } public void addToQueue(MqttMessage msg) { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html index 55f0869dbc..a72718bcb5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html @@ -73,6 +73,12 @@ {{ 'device-profile.mqtt-payload-type-required' | translate }} +
    + + {{ 'device-profile.mqtt-enable-compatibility-with-other-payload-formats' | translate }} + +
    +
    device-profile.telemetry-proto-schema diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts index 5254b7574f..4e97737880 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts @@ -97,7 +97,8 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control deviceTelemetryProtoSchema: [defaultTelemetrySchema, Validators.required], deviceAttributesProtoSchema: [defaultAttributesSchema, Validators.required], deviceRpcRequestProtoSchema: [defaultRpcRequestSchema, Validators.required], - deviceRpcResponseProtoSchema: [defaultRpcResponseSchema, Validators.required] + deviceRpcResponseProtoSchema: [defaultRpcResponseSchema, Validators.required], + enableCompatibilityWithOtherPayloadFormats: [false, Validators.required] }) }, {validator: this.uniqueDeviceTopicValidator} ); @@ -156,7 +157,8 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control deviceTelemetryProtoSchema: defaultTelemetrySchema, deviceAttributesProtoSchema: defaultAttributesSchema, deviceRpcRequestProtoSchema: defaultRpcRequestSchema, - deviceRpcResponseProtoSchema: defaultRpcResponseSchema + deviceRpcResponseProtoSchema: defaultRpcResponseSchema, + enableCompatibilityWithOtherPayloadFormats: false, }, {emitEvent: false}); } if (type === TransportPayloadType.PROTOBUF && !this.disabled) { @@ -164,11 +166,13 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control transportPayloadTypeForm.get('deviceAttributesProtoSchema').enable({emitEvent: false}); transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').enable({emitEvent: false}); transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').enable({emitEvent: false}); + transportPayloadTypeForm.get('enableCompatibilityWithOtherPayloadFormats').enable({emitEvent: false}); } else { transportPayloadTypeForm.get('deviceTelemetryProtoSchema').disable({emitEvent: false}); transportPayloadTypeForm.get('deviceAttributesProtoSchema').disable({emitEvent: false}); transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').disable({emitEvent: false}); transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').disable({emitEvent: false}); + transportPayloadTypeForm.get('enableCompatibilityWithOtherPayloadFormats').disable({emitEvent: false}); } } diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index d27036d7df..806e47b6ce 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -247,6 +247,7 @@ export interface MqttDeviceProfileTransportConfiguration { deviceAttributesTopic?: string; transportPayloadTypeConfiguration?: { transportPayloadType?: TransportPayloadType; + enableCompatibilityWithOtherPayloadFormats?: boolean; }; [key: string]: any; } @@ -359,7 +360,10 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT const mqttTransportConfiguration: MqttDeviceProfileTransportConfiguration = { deviceTelemetryTopic: 'v1/devices/me/telemetry', deviceAttributesTopic: 'v1/devices/me/attributes', - transportPayloadTypeConfiguration: {transportPayloadType: TransportPayloadType.JSON} + transportPayloadTypeConfiguration: { + transportPayloadType: TransportPayloadType.JSON, + enableCompatibilityWithOtherPayloadFormats: false + } }; transportConfiguration = {...mqttTransportConfiguration, type: DeviceTransportType.MQTT}; break; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 16788b9adc..40e5976ed0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1096,6 +1096,8 @@ "mqtt-device-payload-type": "MQTT device payload", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", + "mqtt-enable-compatibility-with-other-payload-formats": "Enable compatibility with other payload formats.", + "mqtt-enable-compatibility-with-other-payload-formats-hint": "When enabled, the platform will use a specified payload format by default. If parsing fails, the platform will attempt to use other available formats. Useful for backward compatibility during firmware updates. For example, the initial release of the firmware uses JSON, while the new release uses Protobuf. During the process of firmware update for the fleet of devices, it is required to support both Protobuf and JSON simultaneously. The compatibility mode introduces slight performance degradation, so it is recommended to disable this mode once all devices are updated.", "snmp-add-mapping": "Add SNMP mapping", "snmp-mapping-not-configured": "No mapping for OID to timeseries/telemetry configured", "snmp-timseries-or-attribute-name": "Timeseries/attribute name for mapping", From 49394fab0e2d97a19b72dfd031d68b6503e8aa86 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 26 Oct 2021 15:13:58 +0300 Subject: [PATCH 141/303] Optimize imports for controllers --- .../controller/AbstractRpcController.java | 4 ++-- .../server/controller/AuthController.java | 8 +++----- .../server/controller/DeviceController.java | 3 --- .../controller/EntityViewController.java | 19 +++++++++++++++++- .../server/controller/Lwm2mController.java | 4 ---- .../server/controller/RpcV2Controller.java | 18 +++++++++++++++-- .../controller/TenantProfileController.java | 14 ++++++++++++- .../server/controller/UserController.java | 20 ++++++++++++++++++- .../controller/WidgetTypeController.java | 4 +++- .../controller/WidgetsBundleController.java | 12 ++++++++++- 10 files changed, 85 insertions(+), 21 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java b/application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java index bb71116d08..5c40461abc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java @@ -25,7 +25,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.context.request.async.DeferredResult; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.rpc.RpcError; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; @@ -34,10 +33,11 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UUIDBased; +import org.thingsboard.server.common.data.rpc.RpcError; import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.service.rpc.LocalRequestMetaData; import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; import org.thingsboard.server.service.security.AccessValidator; diff --git a/application/src/main/java/org/thingsboard/server/controller/AuthController.java b/application/src/main/java/org/thingsboard/server/controller/AuthController.java index ca982dbd3f..e7d553834b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuthController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuthController.java @@ -15,8 +15,6 @@ */ package org.thingsboard.server.controller; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; @@ -50,13 +48,13 @@ import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; +import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails; import org.thingsboard.server.service.security.model.ActivateUserRequest; import org.thingsboard.server.service.security.model.ChangePasswordRequest; +import org.thingsboard.server.service.security.model.JwtTokenPair; import org.thingsboard.server.service.security.model.ResetPasswordEmailRequest; import org.thingsboard.server.service.security.model.ResetPasswordRequest; -import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; -import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails; -import org.thingsboard.server.service.security.model.JwtTokenPair; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.UserPrincipal; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; 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 e50ee8f429..07d6bf06c1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.controller; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -85,7 +84,6 @@ import javax.annotation.Nullable; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; @@ -99,7 +97,6 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFI import static org.thingsboard.server.controller.ControllerConstants.DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TEXT_SEARCH_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TYPE_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java index 431abbd1be..906e0f4dd1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -75,11 +75,28 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.thingsboard.server.controller.ControllerConstants.*; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_INFO_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_INFO_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_TYPE; +import static org.thingsboard.server.controller.ControllerConstants.MODEL_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.EdgeController.EDGE_ID; /** diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 3d60a29645..35131de2f7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -28,18 +28,14 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; -import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.security.permission.Resource; import java.util.Map; -import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index b388f4d7b5..389a767cdf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -52,8 +52,22 @@ import javax.annotation.Nullable; import java.util.UUID; import static org.thingsboard.server.common.data.DataConstants.RPC_DELETED; - -import static org.thingsboard.server.controller.ControllerConstants.*; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RPC_ID; +import static org.thingsboard.server.controller.ControllerConstants.RPC_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RPC_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.RPC_STATUS_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.RPC_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; @RestController @TbCoreComponent diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index a9934c753a..ab52e8ebd4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -40,7 +40,19 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; -import static org.thingsboard.server.controller.ControllerConstants.*; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION; @RestController @TbCoreComponent diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index e7171da3b6..d768a42e16 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -62,7 +62,25 @@ import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.servlet.http.HttpServletRequest; import java.util.List; -import static org.thingsboard.server.controller.ControllerConstants.*; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; +import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEFAULT_DASHBOARD; +import static org.thingsboard.server.controller.ControllerConstants.HOME_DASHBOARD; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.USER_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.USER_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.USER_TEXT_SEARCH_DESCRIPTION; @RequiredArgsConstructor @RestController diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index 35540b3cd2..a899f4cce2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -43,7 +43,9 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.List; -import static org.thingsboard.server.controller.ControllerConstants.*; +import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.WIDGET_TYPE_ID_PARAM_DESCRIPTION; @Slf4j @RestController diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index 747f17c65c..a6cc14dce1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -41,7 +41,17 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.List; -import static org.thingsboard.server.controller.ControllerConstants.*; +import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION; @RestController @TbCoreComponent From 75c1185d186353e789af91a9f6662abbfc3371ce Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 26 Oct 2021 17:25:27 +0300 Subject: [PATCH 142/303] update logic after review --- .../ProtoTransportPayloadConfiguration.java | 3 +- .../transport/mqtt/MqttTransportHandler.java | 44 +++--------- .../server/transport/mqtt/TopicType.java | 20 ++++++ .../BackwardCompatibilityAdaptor.java | 70 +++++++------------ .../mqtt/adaptors/JsonMqttAdaptor.java | 8 +-- .../mqtt/adaptors/MqttTransportAdaptor.java | 18 +++-- .../mqtt/adaptors/ProtoMqttAdaptor.java | 8 +-- .../mqtt/session/DeviceSessionCtx.java | 60 ++++++++++++---- ...ile-transport-configuration.component.html | 12 +++- ...ofile-transport-configuration.component.ts | 54 ++++++++++++-- ui-ngx/src/app/shared/models/device.models.ts | 6 +- .../assets/locale/locale.constant-en_US.json | 6 +- 12 files changed, 186 insertions(+), 123 deletions(-) create mode 100644 common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TopicType.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/ProtoTransportPayloadConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/ProtoTransportPayloadConfiguration.java index 1e45ff3ba6..08a0cdd610 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/ProtoTransportPayloadConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/ProtoTransportPayloadConfiguration.java @@ -54,7 +54,8 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC private String deviceRpcRequestProtoSchema; private String deviceRpcResponseProtoSchema; - private boolean enableCompatibilityWithOtherPayloadFormats; + private boolean enableCompatibilityWithJsonPayloadFormat; + private boolean useJsonPayloadFormatForDefaultDownlinkTopics; @Override public TransportPayloadType getTransportPayloadType() { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 3d04ecfdc9..f9ddbf1058 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -966,29 +966,23 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) { log.trace("[{}] Received get attributes response", sessionId); String topicBase; - MqttTransportAdaptor adaptor; - boolean useBackupAdaptorByDefault = false; + MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(attrReqTopicType); switch (attrReqTopicType) { case V2: - adaptor = deviceSessionCtx.getPayloadAdaptor(); topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_TOPIC_PREFIX; break; case V2_JSON: - adaptor = context.getJsonMqttAdaptor(); topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_JSON_TOPIC_PREFIX; break; case V2_PROTO: - adaptor = context.getProtoMqttAdaptor(); topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_PROTO_TOPIC_PREFIX; break; default: - adaptor = deviceSessionCtx.getPayloadAdaptor(); topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_TOPIC_PREFIX; - useBackupAdaptorByDefault = true; break; } try { - adaptor.convertToPublish(deviceSessionCtx, response, topicBase, useBackupAdaptorByDefault).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); + adaptor.convertToPublish(deviceSessionCtx, response, topicBase).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); } @@ -999,29 +993,23 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement log.trace("[{}] Received attributes update notification to device", sessionId); log.info("[{}] : attrSubTopicType: {}", notification.toString(), attrSubTopicType); String topic; - MqttTransportAdaptor adaptor; - boolean useBackupAdaptorByDefault = false; + MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(attrSubTopicType); switch (attrSubTopicType) { case V2: - adaptor = deviceSessionCtx.getPayloadAdaptor(); topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC; break; case V2_JSON: - adaptor = context.getJsonMqttAdaptor(); topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC; break; case V2_PROTO: - adaptor = context.getProtoMqttAdaptor(); topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC; break; default: - adaptor = deviceSessionCtx.getPayloadAdaptor(); topic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC; - useBackupAdaptorByDefault = true; break; } try { - adaptor.convertToPublish(deviceSessionCtx, notification, topic, useBackupAdaptorByDefault).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); + adaptor.convertToPublish(deviceSessionCtx, notification, topic).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { log.trace("[{}] Failed to convert device attributes update to MQTT msg", sessionId, e); } @@ -1037,29 +1025,23 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { log.info("[{}] Received RPC command to device", sessionId); String baseTopic; - MqttTransportAdaptor adaptor; - boolean useBackupAdaptorByDefault = false; + MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(rpcSubTopicType); switch (rpcSubTopicType) { case V2: - adaptor = deviceSessionCtx.getPayloadAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_TOPIC; break; case V2_JSON: - adaptor = context.getJsonMqttAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_JSON_TOPIC; break; case V2_PROTO: - adaptor = context.getProtoMqttAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_PROTO_TOPIC; break; default: - adaptor = deviceSessionCtx.getPayloadAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_TOPIC; - useBackupAdaptorByDefault = true; break; } try { - adaptor.convertToPublish(deviceSessionCtx, rpcRequest, baseTopic, useBackupAdaptorByDefault).ifPresent(payload -> { + adaptor.convertToPublish(deviceSessionCtx, rpcRequest, baseTopic).ifPresent(payload -> { int msgId = ((MqttPublishMessage) payload).variableHeader().packetId(); if (isAckExpected(payload)) { rpcAwaitingAck.put(msgId, rpcRequest); @@ -1095,29 +1077,23 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg rpcResponse) { log.trace("[{}] Received RPC response from server", sessionId); String baseTopic; - MqttTransportAdaptor adaptor; - boolean useBackupAdaptorByDefault = false; + MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(toServerRpcSubTopicType); switch (toServerRpcSubTopicType) { case V2: - adaptor = deviceSessionCtx.getPayloadAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_TOPIC; break; case V2_JSON: - adaptor = context.getJsonMqttAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_JSON_TOPIC; break; case V2_PROTO: - adaptor = context.getProtoMqttAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_PROTO_TOPIC; break; default: - adaptor = deviceSessionCtx.getPayloadAdaptor(); baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_TOPIC; - useBackupAdaptorByDefault = true; break; } try { - adaptor.convertToPublish(deviceSessionCtx, rpcResponse, baseTopic, useBackupAdaptorByDefault).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); + adaptor.convertToPublish(deviceSessionCtx, rpcResponse, baseTopic).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { log.trace("[{}] Failed to convert device RPC command to MQTT msg", sessionId, e); } @@ -1141,8 +1117,4 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement deviceSessionCtx.onDeviceUpdate(sessionInfo, device, deviceProfileOpt); } - private enum TopicType { - V1, V2, V2_JSON, V2_PROTO - } - } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TopicType.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TopicType.java new file mode 100644 index 0000000000..e2f427261e --- /dev/null +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TopicType.java @@ -0,0 +1,20 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt; + +public enum TopicType { + V1, V2, V2_JSON, V2_PROTO +} diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java index 4b3a3e25b5..141332f7a7 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java @@ -32,108 +32,86 @@ import java.util.Optional; @Slf4j public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { - private static final String BACKWARD_COMPATIBILITY_ENABLED = "Other payload formats compatibility enabled! Trying to convert "; - - private MqttTransportAdaptor main; - private MqttTransportAdaptor backup; + private MqttTransportAdaptor protoAdaptor; + private MqttTransportAdaptor jsonAdaptor; @Override public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { try { - return main.convertToPostTelemetry(ctx, inbound); + return protoAdaptor.convertToPostTelemetry(ctx, inbound); } catch (AdaptorException e) { - log.trace(BACKWARD_COMPATIBILITY_ENABLED + "post telemetry request msg using {} ...", backup.getClass().getSimpleName()); - return backup.convertToPostTelemetry(ctx, inbound); + log.trace("failed to process post telemetry request msg {} due to: ", inbound, e); + return jsonAdaptor.convertToPostTelemetry(ctx, inbound); } } @Override public TransportProtos.PostAttributeMsg convertToPostAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { try { - return main.convertToPostAttributes(ctx, inbound); + return protoAdaptor.convertToPostAttributes(ctx, inbound); } catch (AdaptorException e) { - log.trace(BACKWARD_COMPATIBILITY_ENABLED + "post attributes request msg using {} ...", backup.getClass().getSimpleName()); - return backup.convertToPostAttributes(ctx, inbound); + log.trace("failed to process post attributes request msg {} due to: ", inbound, e); + return jsonAdaptor.convertToPostAttributes(ctx, inbound); } } @Override public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { try { - return main.convertToGetAttributes(ctx, inbound, topicBase); + return protoAdaptor.convertToGetAttributes(ctx, inbound, topicBase); } catch (AdaptorException e) { - log.trace(BACKWARD_COMPATIBILITY_ENABLED + "get attributes request msg using {} ...", backup.getClass().getSimpleName()); - return backup.convertToGetAttributes(ctx, inbound, topicBase); + log.trace("failed to process get attributes request msg {} due to: ", inbound, e); + return jsonAdaptor.convertToGetAttributes(ctx, inbound, topicBase); } } @Override public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(MqttDeviceAwareSessionContext ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException { try { - return main.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); + return protoAdaptor.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); } catch (AdaptorException e) { - log.trace(BACKWARD_COMPATIBILITY_ENABLED + "to device rpc response msg using {} ...", backup.getClass().getSimpleName()); - return backup.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); + log.trace("failed to process to device rpc response msg {} due to: ", mqttMsg, e); + return jsonAdaptor.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); } } @Override public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(MqttDeviceAwareSessionContext ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException { try { - return main.convertToServerRpcRequest(ctx, mqttMsg, topicBase); + return protoAdaptor.convertToServerRpcRequest(ctx, mqttMsg, topicBase); } catch (AdaptorException e) { - log.trace(BACKWARD_COMPATIBILITY_ENABLED + "to server rpc request msg using {} ...", backup.getClass().getSimpleName()); - return backup.convertToServerRpcRequest(ctx, mqttMsg, topicBase); + log.trace("failed to process to server rpc request msg {} due to: ", mqttMsg, e); + return jsonAdaptor.convertToServerRpcRequest(ctx, mqttMsg, topicBase); } } @Override public TransportProtos.ClaimDeviceMsg convertToClaimDevice(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { try { - return main.convertToClaimDevice(ctx, inbound); + return protoAdaptor.convertToClaimDevice(ctx, inbound); } catch (AdaptorException e) { - log.trace(BACKWARD_COMPATIBILITY_ENABLED + "claim device request msg using {} ...", backup.getClass().getSimpleName()); - return backup.convertToClaimDevice(ctx, inbound); + log.trace("failed to process claim device request msg {} due to: ", inbound, e); + return jsonAdaptor.convertToClaimDevice(ctx, inbound); } } - @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { - return useBackupAdaptorByDefault ? backup.convertToPublish(ctx, responseMsg, topicBase, false) : main.convertToPublish(ctx, responseMsg, topicBase, false); - } - @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { - return main.convertToGatewayPublish(ctx, deviceName, responseMsg); - } - - @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic, boolean useBackupAdaptorByDefault) throws AdaptorException { - return useBackupAdaptorByDefault ? backup.convertToPublish(ctx, notificationMsg, topic, false) : main.convertToPublish(ctx, notificationMsg, topic, false); + return protoAdaptor.convertToGatewayPublish(ctx, deviceName, responseMsg); } @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException { - return main.convertToGatewayPublish(ctx, deviceName, notificationMsg); - } - - @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { - return useBackupAdaptorByDefault ? backup.convertToPublish(ctx, rpcRequest, topicBase, false) : main.convertToPublish(ctx, rpcRequest, topicBase, false); + return protoAdaptor.convertToGatewayPublish(ctx, deviceName, notificationMsg); } @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException { - return main.convertToGatewayPublish(ctx, deviceName, rpcRequest); - } - - @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { - return useBackupAdaptorByDefault ? backup.convertToPublish(ctx, rpcResponse, topicBase, false) : main.convertToPublish(ctx, rpcResponse, topicBase, false); + return protoAdaptor.convertToGatewayPublish(ctx, deviceName, rpcRequest); } @Override public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException { - return main.convertToPublish(ctx, firmwareChunk, requestId, chunk, firmwareType); + return protoAdaptor.convertToPublish(ctx, firmwareChunk, requestId, chunk, firmwareType); } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index 68d80538c1..dc2b74a8ea 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -117,7 +117,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { return processConvertFromAttributeResponseMsg(ctx, responseMsg, topicBase); } @@ -127,7 +127,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic, boolean useBackupAdaptorByDefault) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { return Optional.of(createMqttPublishMsg(ctx, topic, JsonConverter.toJson(notificationMsg))); } @@ -138,7 +138,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase, boolean useBackupAdaptorByDefault) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase) { return Optional.of(createMqttPublishMsg(ctx, topicBase + rpcRequest.getRequestId(), JsonConverter.toJson(rpcRequest, false))); } @@ -148,7 +148,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase, boolean useBackupAdaptorByDefault) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) { return Optional.of(createMqttPublishMsg(ctx, topicBase + rpcResponse.getRequestId(), JsonConverter.toJson(rpcResponse))); } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java index f030dd9fca..1543b5c6c7 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java @@ -60,27 +60,33 @@ public interface MqttTransportAdaptor { ClaimDeviceMsg convertToClaimDevice(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException; + default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { + return Optional.empty(); + } Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, GetAttributeResponseMsg responseMsg) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic, boolean useBackupAdaptorByDefault) throws AdaptorException; + default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException { + return Optional.empty(); + } Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException; + default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException { + return Optional.empty(); + } Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException; + default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException { + return Optional.empty(); + } default ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { - // method is never used in BackwardCompatibilityAdaptor return null; } default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException { - // method is never used in BackwardCompatibilityAdaptor return Optional.empty(); } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java index 7f9b326f9d..4fa47b367d 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java @@ -135,7 +135,7 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { if (!StringUtils.isEmpty(responseMsg.getError())) { throw new AdaptorException(responseMsg.getError()); } else { @@ -148,7 +148,7 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase, boolean useBackupAdaptorByDefault) throws AdaptorException { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException { DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx; DynamicMessage.Builder rpcRequestDynamicMessageBuilder = deviceSessionCtx.getRpcRequestDynamicMessageBuilder(); if (rpcRequestDynamicMessageBuilder == null) { @@ -159,12 +159,12 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase, boolean useBackupAdaptorByDefault) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) { return Optional.of(createMqttPublishMsg(ctx, topicBase + rpcResponse.getRequestId(), rpcResponse.toByteArray())); } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic, boolean useBackupAdaptorByDefault) { + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { return Optional.of(createMqttPublishMsg(ctx, topic, notificationMsg.toByteArray())); } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java index cc65da1008..585587d6f0 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.mqtt.MqttTransportContext; +import org.thingsboard.server.transport.mqtt.TopicType; import org.thingsboard.server.transport.mqtt.adaptors.BackwardCompatibilityAdaptor; import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; import org.thingsboard.server.transport.mqtt.util.MqttTopicFilter; @@ -39,7 +40,6 @@ import org.thingsboard.server.transport.mqtt.util.MqttTopicFilterFactory; import java.util.Collection; import java.util.Collections; -import java.util.Queue; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; @@ -77,11 +77,14 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { private volatile MqttTopicFilter telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter(); private volatile MqttTopicFilter attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter(); private volatile TransportPayloadType payloadType = TransportPayloadType.JSON; - private volatile boolean payloadFormatsCompatipilityEnabled; private volatile Descriptors.Descriptor attributesDynamicMessageDescriptor; private volatile Descriptors.Descriptor telemetryDynamicMessageDescriptor; private volatile Descriptors.Descriptor rpcResponseDynamicMessageDescriptor; private volatile DynamicMessage.Builder rpcRequestDynamicMessageBuilder; + private volatile MqttTransportAdaptor adaptor; + private volatile boolean jsonPayloadFormatCompatibilityEnabled; + private volatile boolean useJsonPayloadFormatForDefaultDownlinkTopics; + @Getter @Setter @@ -90,6 +93,7 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { public DeviceSessionCtx(UUID sessionId, ConcurrentMap mqttQoSMap, MqttTransportContext context) { super(sessionId, mqttQoSMap); this.context = context; + this.adaptor = context.getJsonMqttAdaptor(); } public int nextMsgId() { @@ -105,15 +109,7 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { } public MqttTransportAdaptor getPayloadAdaptor() { - if (payloadType.equals(TransportPayloadType.JSON)) { - return context.getJsonMqttAdaptor(); - } else { - if (payloadFormatsCompatipilityEnabled) { - return new BackwardCompatibilityAdaptor(context.getProtoMqttAdaptor(), context.getJsonMqttAdaptor()); - } else { - return context.getProtoMqttAdaptor(); - } - } + return adaptor; } public boolean isJsonPayloadType() { @@ -140,12 +136,14 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { public void setDeviceProfile(DeviceProfile deviceProfile) { super.setDeviceProfile(deviceProfile); updateTopicFilters(deviceProfile); + updateAdaptor(); } @Override public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { super.onDeviceProfileUpdate(sessionInfo, deviceProfile); updateTopicFilters(deviceProfile); + updateAdaptor(); } private void updateTopicFilters(DeviceProfile deviceProfile) { @@ -158,7 +156,10 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { telemetryTopicFilter = MqttTopicFilterFactory.toFilter(mqttConfig.getDeviceTelemetryTopic()); attributesTopicFilter = MqttTopicFilterFactory.toFilter(mqttConfig.getDeviceAttributesTopic()); if (TransportPayloadType.PROTOBUF.equals(payloadType)) { - updateDynamicMessageDescriptors(transportPayloadTypeConfiguration); + ProtoTransportPayloadConfiguration protoTransportPayloadConfig = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; + updateDynamicMessageDescriptors(protoTransportPayloadConfig); + jsonPayloadFormatCompatibilityEnabled = protoTransportPayloadConfig.isEnableCompatibilityWithJsonPayloadFormat(); + useJsonPayloadFormatForDefaultDownlinkTopics = protoTransportPayloadConfig.isUseJsonPayloadFormatForDefaultDownlinkTopics(); } } else { telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter(); @@ -166,13 +167,42 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { } } - private void updateDynamicMessageDescriptors(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration) { - ProtoTransportPayloadConfiguration protoTransportPayloadConfig = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; + private void updateDynamicMessageDescriptors(ProtoTransportPayloadConfiguration protoTransportPayloadConfig) { telemetryDynamicMessageDescriptor = protoTransportPayloadConfig.getTelemetryDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceTelemetryProtoSchema()); attributesDynamicMessageDescriptor = protoTransportPayloadConfig.getAttributesDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceAttributesProtoSchema()); rpcResponseDynamicMessageDescriptor = protoTransportPayloadConfig.getRpcResponseDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceRpcResponseProtoSchema()); rpcRequestDynamicMessageBuilder = protoTransportPayloadConfig.getRpcRequestDynamicMessageBuilder(protoTransportPayloadConfig.getDeviceRpcRequestProtoSchema()); - payloadFormatsCompatipilityEnabled = protoTransportPayloadConfig.isEnableCompatibilityWithOtherPayloadFormats(); + } + + public MqttTransportAdaptor getAdaptor(TopicType topicType) { + switch (topicType) { + case V2: + return getProfileAdaptor(); + case V2_JSON: + return context.getJsonMqttAdaptor(); + case V2_PROTO: + return context.getProtoMqttAdaptor(); + default: + return useJsonPayloadFormatForDefaultDownlinkTopics ? context.getJsonMqttAdaptor() : getProfileAdaptor(); + } + } + + private MqttTransportAdaptor getProfileAdaptor() { + return isJsonPayloadType() ? context.getJsonMqttAdaptor() : context.getProtoMqttAdaptor(); + } + + private void updateAdaptor() { + if (isJsonPayloadType()) { + adaptor = context.getJsonMqttAdaptor(); + jsonPayloadFormatCompatibilityEnabled = false; + useJsonPayloadFormatForDefaultDownlinkTopics = false; + } else { + if (jsonPayloadFormatCompatibilityEnabled) { + adaptor = new BackwardCompatibilityAdaptor(context.getProtoMqttAdaptor(), context.getJsonMqttAdaptor()); + } else { + adaptor = context.getProtoMqttAdaptor(); + } + } } public void addToQueue(MqttMessage msg) { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html index a72718bcb5..5f49053c42 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html @@ -74,10 +74,16 @@
    - - {{ 'device-profile.mqtt-enable-compatibility-with-other-payload-formats' | translate }} + + {{ 'device-profile.mqtt-enable-compatibility-with-json-payload-format' | translate }} -
    +
    +
    + + {{ 'device-profile.mqtt-use-json-format-for-default-downlink-topics' | translate }} + +
    +
    diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts index 4e97737880..a8da7cc4e7 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts @@ -98,7 +98,8 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control deviceAttributesProtoSchema: [defaultAttributesSchema, Validators.required], deviceRpcRequestProtoSchema: [defaultRpcRequestSchema, Validators.required], deviceRpcResponseProtoSchema: [defaultRpcResponseSchema, Validators.required], - enableCompatibilityWithOtherPayloadFormats: [false, Validators.required] + enableCompatibilityWithJsonPayloadFormat: [false, Validators.required], + useJsonPayloadFormatForDefaultDownlinkTopics: [false, Validators.required] }) }, {validator: this.uniqueDeviceTopicValidator} ); @@ -107,6 +108,14 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control ).subscribe(payloadType => { this.updateTransportPayloadBasedControls(payloadType, true); }); + this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.enableCompatibilityWithJsonPayloadFormat') + .valueChanges.pipe(takeUntil(this.destroy$) + ).subscribe(compatibilityWithJsonPayloadFormatEnabled => { + if (!compatibilityWithJsonPayloadFormatEnabled) { + this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.useJsonPayloadFormatForDefaultDownlinkTopics') + .patchValue(false, {emitEvent: false}); + } + }); this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.pipe( takeUntil(this.destroy$) ).subscribe(() => { @@ -133,6 +142,10 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control return transportPayloadType === TransportPayloadType.PROTOBUF; } + get compatibilityWithJsonPayloadFormatEnabled(): boolean { + return this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.enableCompatibilityWithJsonPayloadFormat').value; + } + writeValue(value: MqttDeviceProfileTransportConfiguration | null): void { if (isDefinedAndNotNull(value)) { this.mqttDeviceProfileTransportConfigurationFormGroup.patchValue(value, {emitEvent: false}); @@ -149,6 +162,36 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control this.propagateChange(configuration); } + private updateTest(type: TransportPayloadType, forceUpdated = false) { + const transportPayloadTypeForm = this.mqttDeviceProfileTransportConfigurationFormGroup + .get('transportPayloadTypeConfiguration') as FormGroup; + if (forceUpdated) { + transportPayloadTypeForm.patchValue({ + deviceTelemetryProtoSchema: defaultTelemetrySchema, + deviceAttributesProtoSchema: defaultAttributesSchema, + deviceRpcRequestProtoSchema: defaultRpcRequestSchema, + deviceRpcResponseProtoSchema: defaultRpcResponseSchema, + enableCompatibilityWithJsonPayloadFormat: false, + useJsonPayloadFormatForDefaultDownlinkTopics: false + }, {emitEvent: false}); + } + if (type === TransportPayloadType.PROTOBUF && !this.disabled) { + transportPayloadTypeForm.get('deviceTelemetryProtoSchema').enable({emitEvent: false}); + transportPayloadTypeForm.get('deviceAttributesProtoSchema').enable({emitEvent: false}); + transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').enable({emitEvent: false}); + transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').enable({emitEvent: false}); + transportPayloadTypeForm.get('enableCompatibilityWithJsonPayloadFormat').enable({emitEvent: false}); + transportPayloadTypeForm.get('useJsonPayloadFormatForDefaultDownlinkTopics').enable({emitEvent: false}); + } else { + transportPayloadTypeForm.get('deviceTelemetryProtoSchema').disable({emitEvent: false}); + transportPayloadTypeForm.get('deviceAttributesProtoSchema').disable({emitEvent: false}); + transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').disable({emitEvent: false}); + transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').disable({emitEvent: false}); + transportPayloadTypeForm.get('enableCompatibilityWithJsonPayloadFormat').disable({emitEvent: false}); + transportPayloadTypeForm.get('useJsonPayloadFormatForDefaultDownlinkTopics').disable({emitEvent: false}); + } + } + private updateTransportPayloadBasedControls(type: TransportPayloadType, forceUpdated = false) { const transportPayloadTypeForm = this.mqttDeviceProfileTransportConfigurationFormGroup .get('transportPayloadTypeConfiguration') as FormGroup; @@ -158,7 +201,8 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control deviceAttributesProtoSchema: defaultAttributesSchema, deviceRpcRequestProtoSchema: defaultRpcRequestSchema, deviceRpcResponseProtoSchema: defaultRpcResponseSchema, - enableCompatibilityWithOtherPayloadFormats: false, + enableCompatibilityWithJsonPayloadFormat: false, + useJsonPayloadFormatForDefaultDownlinkTopics: false }, {emitEvent: false}); } if (type === TransportPayloadType.PROTOBUF && !this.disabled) { @@ -166,13 +210,15 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control transportPayloadTypeForm.get('deviceAttributesProtoSchema').enable({emitEvent: false}); transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').enable({emitEvent: false}); transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').enable({emitEvent: false}); - transportPayloadTypeForm.get('enableCompatibilityWithOtherPayloadFormats').enable({emitEvent: false}); + transportPayloadTypeForm.get('enableCompatibilityWithJsonPayloadFormat').enable({emitEvent: false}); + transportPayloadTypeForm.get('useJsonPayloadFormatForDefaultDownlinkTopics').enable({emitEvent: false}); } else { transportPayloadTypeForm.get('deviceTelemetryProtoSchema').disable({emitEvent: false}); transportPayloadTypeForm.get('deviceAttributesProtoSchema').disable({emitEvent: false}); transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').disable({emitEvent: false}); transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').disable({emitEvent: false}); - transportPayloadTypeForm.get('enableCompatibilityWithOtherPayloadFormats').disable({emitEvent: false}); + transportPayloadTypeForm.get('enableCompatibilityWithJsonPayloadFormat').disable({emitEvent: false}); + transportPayloadTypeForm.get('useJsonPayloadFormatForDefaultDownlinkTopics').disable({emitEvent: false}); } } diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 806e47b6ce..7ebf7bde47 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -247,7 +247,8 @@ export interface MqttDeviceProfileTransportConfiguration { deviceAttributesTopic?: string; transportPayloadTypeConfiguration?: { transportPayloadType?: TransportPayloadType; - enableCompatibilityWithOtherPayloadFormats?: boolean; + enableCompatibilityWithJsonPayloadFormat?: boolean; + useJsonPayloadFormatForDefaultDownlinkTopics?: boolean; }; [key: string]: any; } @@ -362,7 +363,8 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT deviceAttributesTopic: 'v1/devices/me/attributes', transportPayloadTypeConfiguration: { transportPayloadType: TransportPayloadType.JSON, - enableCompatibilityWithOtherPayloadFormats: false + enableCompatibilityWithJsonPayloadFormat: false, + useJsonPayloadFormatForDefaultDownlinkTopics: false, } }; transportConfiguration = {...mqttTransportConfiguration, type: DeviceTransportType.MQTT}; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 40e5976ed0..85a685aa4b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1096,8 +1096,10 @@ "mqtt-device-payload-type": "MQTT device payload", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", - "mqtt-enable-compatibility-with-other-payload-formats": "Enable compatibility with other payload formats.", - "mqtt-enable-compatibility-with-other-payload-formats-hint": "When enabled, the platform will use a specified payload format by default. If parsing fails, the platform will attempt to use other available formats. Useful for backward compatibility during firmware updates. For example, the initial release of the firmware uses JSON, while the new release uses Protobuf. During the process of firmware update for the fleet of devices, it is required to support both Protobuf and JSON simultaneously. The compatibility mode introduces slight performance degradation, so it is recommended to disable this mode once all devices are updated.", + "mqtt-enable-compatibility-with-json-payload-format": "Enable compatibility with other payload formats.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "When enabled, the platform will use a Protobuf payload format by default. If parsing fails, the platform will attempt to use JSON payload format. Useful for backward compatibility during firmware updates. For example, the initial release of the firmware uses Json, while the new release uses Protobuf. During the process of firmware update for the fleet of devices, it is required to support both Protobuf and JSON simultaneously. The compatibility mode introduces slight performance degradation, so it is recommended to disable this mode once all devices are updated.", + "mqtt-use-json-format-for-default-downlink-topics": "Use Json format for default downlink topics", + "mqtt-use-json-format-for-default-downlink-topics-hint": "When enabled, the platform will use Json payload format to push attributes and RPC via the following topics: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. This setting does not impact attribute and rpc subscriptions sent using new (v2) topics: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. $request_id is an integer request identifier.", "snmp-add-mapping": "Add SNMP mapping", "snmp-mapping-not-configured": "No mapping for OID to timeseries/telemetry configured", "snmp-timseries-or-attribute-name": "Timeseries/attribute name for mapping", From 0f71d0d8fc528a01d5c1cdb08f14dd43429cc2b3 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 26 Oct 2021 17:31:05 +0300 Subject: [PATCH 143/303] fix typos --- .../BackwardCompatibilityAdaptor.java | 12 ++++---- .../mqtt/session/DeviceSessionCtx.java | 1 - ...ofile-transport-configuration.component.ts | 30 ------------------- 3 files changed, 6 insertions(+), 37 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java index 141332f7a7..55733f7b81 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java @@ -40,7 +40,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToPostTelemetry(ctx, inbound); } catch (AdaptorException e) { - log.trace("failed to process post telemetry request msg {} due to: ", inbound, e); + log.trace("failed to process post telemetry request msg: {} due to: ", inbound, e); return jsonAdaptor.convertToPostTelemetry(ctx, inbound); } } @@ -50,7 +50,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToPostAttributes(ctx, inbound); } catch (AdaptorException e) { - log.trace("failed to process post attributes request msg {} due to: ", inbound, e); + log.trace("failed to process post attributes request msg: {} due to: ", inbound, e); return jsonAdaptor.convertToPostAttributes(ctx, inbound); } } @@ -60,7 +60,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToGetAttributes(ctx, inbound, topicBase); } catch (AdaptorException e) { - log.trace("failed to process get attributes request msg {} due to: ", inbound, e); + log.trace("failed to process get attributes request msg: {} due to: ", inbound, e); return jsonAdaptor.convertToGetAttributes(ctx, inbound, topicBase); } } @@ -70,7 +70,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); } catch (AdaptorException e) { - log.trace("failed to process to device rpc response msg {} due to: ", mqttMsg, e); + log.trace("failed to process to device rpc response msg: {} due to: ", mqttMsg, e); return jsonAdaptor.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); } } @@ -80,7 +80,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToServerRpcRequest(ctx, mqttMsg, topicBase); } catch (AdaptorException e) { - log.trace("failed to process to server rpc request msg {} due to: ", mqttMsg, e); + log.trace("failed to process to server rpc request msg: {} due to: ", mqttMsg, e); return jsonAdaptor.convertToServerRpcRequest(ctx, mqttMsg, topicBase); } } @@ -90,7 +90,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToClaimDevice(ctx, inbound); } catch (AdaptorException e) { - log.trace("failed to process claim device request msg {} due to: ", inbound, e); + log.trace("failed to process claim device request msg: {} due to: ", inbound, e); return jsonAdaptor.convertToClaimDevice(ctx, inbound); } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java index 585587d6f0..601018f574 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java @@ -85,7 +85,6 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { private volatile boolean jsonPayloadFormatCompatibilityEnabled; private volatile boolean useJsonPayloadFormatForDefaultDownlinkTopics; - @Getter @Setter private TransportPayloadType provisionPayloadType = payloadType; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts index a8da7cc4e7..61f72f6c60 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts @@ -162,36 +162,6 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control this.propagateChange(configuration); } - private updateTest(type: TransportPayloadType, forceUpdated = false) { - const transportPayloadTypeForm = this.mqttDeviceProfileTransportConfigurationFormGroup - .get('transportPayloadTypeConfiguration') as FormGroup; - if (forceUpdated) { - transportPayloadTypeForm.patchValue({ - deviceTelemetryProtoSchema: defaultTelemetrySchema, - deviceAttributesProtoSchema: defaultAttributesSchema, - deviceRpcRequestProtoSchema: defaultRpcRequestSchema, - deviceRpcResponseProtoSchema: defaultRpcResponseSchema, - enableCompatibilityWithJsonPayloadFormat: false, - useJsonPayloadFormatForDefaultDownlinkTopics: false - }, {emitEvent: false}); - } - if (type === TransportPayloadType.PROTOBUF && !this.disabled) { - transportPayloadTypeForm.get('deviceTelemetryProtoSchema').enable({emitEvent: false}); - transportPayloadTypeForm.get('deviceAttributesProtoSchema').enable({emitEvent: false}); - transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').enable({emitEvent: false}); - transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').enable({emitEvent: false}); - transportPayloadTypeForm.get('enableCompatibilityWithJsonPayloadFormat').enable({emitEvent: false}); - transportPayloadTypeForm.get('useJsonPayloadFormatForDefaultDownlinkTopics').enable({emitEvent: false}); - } else { - transportPayloadTypeForm.get('deviceTelemetryProtoSchema').disable({emitEvent: false}); - transportPayloadTypeForm.get('deviceAttributesProtoSchema').disable({emitEvent: false}); - transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').disable({emitEvent: false}); - transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').disable({emitEvent: false}); - transportPayloadTypeForm.get('enableCompatibilityWithJsonPayloadFormat').disable({emitEvent: false}); - transportPayloadTypeForm.get('useJsonPayloadFormatForDefaultDownlinkTopics').disable({emitEvent: false}); - } - } - private updateTransportPayloadBasedControls(type: TransportPayloadType, forceUpdated = false) { const transportPayloadTypeForm = this.mqttDeviceProfileTransportConfigurationFormGroup .get('transportPayloadTypeConfiguration') as FormGroup; From 362ccf9f31a026a7195eb42c2774402e7767bc74 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 26 Oct 2021 19:40:38 +0300 Subject: [PATCH 144/303] Unified transport SSL credentials --- .../LwM2MServerSecurityInfoRepository.java | 26 +-- .../src/main/resources/thingsboard.yml | 145 ++++++++++--- .../server/coapserver/TbCoapDtlsSettings.java | 37 ++-- .../server/common/data/ResourceUtils.java | 24 +++ .../LwM2MTransportBootstrapService.java | 52 ++--- .../lwm2m/config/LwM2MSecureServerConfig.java | 6 +- .../config/LwM2MTransportBootstrapConfig.java | 24 ++- .../config/LwM2MTransportServerConfig.java | 69 +++---- .../TbLwM2MDtlsCertificateVerifier.java | 8 +- .../server/DefaultLwM2mTransportService.java | 27 +-- .../mqtt/MqttSslHandlerProvider.java | 42 ++-- common/transport/transport-api/pom.xml | 8 + .../config/ssl/AbstractSslCredentials.java | 191 ++++++++++++++++++ .../config/ssl/KeystoreSslCredentials.java | 52 +++++ .../config/ssl/PemSslCredentials.java | 130 ++++++++++++ .../transport/config/ssl/SslCredentials.java | 45 +++++ .../config/ssl/SslCredentialsConfig.java | 66 ++++++ .../config/ssl/SslCredentialsType.java | 21 ++ .../src/main/resources/tb-coap-transport.yml | 36 +++- .../src/main/resources/tb-lwm2m-transport.yml | 83 ++++++-- .../src/main/resources/tb-mqtt-transport.yml | 30 ++- 21 files changed, 883 insertions(+), 239 deletions(-) create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsConfig.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsType.java diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java index b4ac3d30fd..fcf68bf13a 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java @@ -22,28 +22,11 @@ import org.eclipse.leshan.core.util.Hex; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import java.math.BigInteger; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.KeySpec; - @Slf4j @Service @RequiredArgsConstructor @@ -72,10 +55,9 @@ public class LwM2MServerSecurityInfoRepository { private String getPublicKey(LwM2MSecureServerConfig config) { try { - KeyStore keyStore = serverConfig.getKeyStoreValue(); - if (keyStore != null) { - X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(config.getCertificateAlias()); - return Hex.encodeHexString(serverCertificate.getPublicKey().getEncoded()); + SslCredentials sslCredentials = config.getSslCredentials(); + if (sslCredentials != null) { + return Hex.encodeHexString(sslCredentials.getPublicKey().getEncoded()); } } catch (Exception e) { log.trace("Failed to fetch public key from key store!", e); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 57a6a638af..f88d5f297c 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -619,14 +619,28 @@ transport: bind_port: "${MQTT_SSL_BIND_PORT:8883}" # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}" - # Path to the key store that holds the SSL certificate - key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" - # Password used to access the key store - key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" - # Type of the key store - key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${MQTT_SSL_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}" + # Path to the server certificate private key file (optional) + key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}" + # Server certificate private key password (optional) + key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the SSL certificate + store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" + # Password used to access the key store + store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" # Local CoAP transport parameters @@ -645,14 +659,30 @@ transport: bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" # CoAP DTLS bind port bind_port: "${COAP_DTLS_BIND_PORT:5684}" - # Path to the key store that holds the certificate - key_store: "${COAP_DTLS_KEY_STORE:coapserver.jks}" - # Password used to access the key store - key_store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" - # Key alias - key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}" + # Server DTLS credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${COAP_DTLS_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}" + # Path to the server certificate private key file (optional) + key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}" + # Server certificate private key password (optional) + key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${COAP_DTLS_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the SSL certificate + store_file: "${COAP_DTLS_KEY_STORE:coapserver.jks}" + # Password used to access the key store + store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" + # Key alias + key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}" x509: # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" @@ -669,9 +699,33 @@ transport: security: bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}" + # Server X509 Certificates support + credentials: + # Whether to enable LWM2M server X509 Certificate/RPK support + enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}" + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}" + # Path to the server certificate private key file (optional) + key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}" + # Server certificate private key password (optional) + key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${LWM2M_SERVER_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the SSL certificate + store_file: "${LWM2M_SERVER_KEY_STORE:lwm2mserver.jks}" + # Password used to access the key store + store_password: "${LWM2M_SERVER_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_key_password}" + # Key alias + key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" # Only Certificate_x509: - key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" - key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}" skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" bootstrap: enable: "${LWM2M_ENABLED_BS:true}" @@ -681,18 +735,51 @@ transport: security: bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}" - # Only Certificate_x509: - key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}" - key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}" + # Bootstrap server X509 Certificates support + credentials: + # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support + enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}" + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}" + # Path to the server certificate private key file (optional) + key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}" + # Server certificate private key password (optional) + key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${LWM2M_BS_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the SSL certificate + store_file: "${LWM2M_BS_KEY_STORE:lwm2mserver.jks}" + # Password used to access the key store + store_password: "${LWM2M_BS_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${LWM2M_BS_KEY_PASSWORD:server_key_password}" + # Key alias + key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}" security: - # Certificate_x509: - # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format - # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh - key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" - # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks" - key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}" - key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}" - root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}" + # X509 trust certificates + trust-credentials: + # Whether to load X509 trust certificates + enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}" + # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore) + type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}" + # PEM certificates + pem: + # Path to the certificates file (holds trust certificates) + cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mserver.pem}" + # Keystore with trust certificates + keystore: + # Type of the key store + type: "${LWM2M_TRUST_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the X509 certificates + store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mserver.jks}" + # Password used to access the key store + store_password: "${LWM2M_TRUST_KEY_STORE_PASSWORD:server_ks_password}" recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" timeout: "${LWM2M_TIMEOUT:120000}" diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java index f433909242..6f82c79041 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java @@ -20,11 +20,16 @@ import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; +import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import java.io.IOException; @@ -45,17 +50,15 @@ public class TbCoapDtlsSettings { @Value("${transport.coap.dtls.bind_port}") private Integer port; - @Value("${transport.coap.dtls.key_store}") - private String keyStoreFile; - - @Value("${transport.coap.dtls.key_store_password}") - private String keyStorePassword; - - @Value("${transport.coap.dtls.key_password}") - private String keyPassword; + @Bean + @ConfigurationProperties(prefix = "transport.coap.dtls.credentials") + public SslCredentialsConfig coapDtlsCredentials() { + return new SslCredentialsConfig("COAP DTLS Credentials", false); + } - @Value("${transport.coap.dtls.key_alias}") - private String keyAlias; + @Autowired + @Qualifier("coapDtlsCredentials") + private SslCredentialsConfig coapDtlsCredentialsConfig; @Value("${transport.coap.dtls.x509.skip_validity_check_for_client_cert:false}") private boolean skipValidityCheckForClientCert; @@ -75,8 +78,9 @@ public class TbCoapDtlsSettings { public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException { DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(); configBuilder.setAddress(getInetSocketAddress()); - String keyStoreFilePath = ResourceUtils.getUri(this, keyStoreFile); - SslContextUtil.Credentials serverCredentials = loadServerCredentials(keyStoreFilePath); + SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials(); + SslContextUtil.Credentials serverCredentials = + new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain()); configBuilder.setServerOnly(true); configBuilder.setClientAuthenticationRequired(false); configBuilder.setClientAuthenticationWanted(true); @@ -94,15 +98,6 @@ public class TbCoapDtlsSettings { return configBuilder.build(); } - private SslContextUtil.Credentials loadServerCredentials(String keyStoreFilePath) { - try { - return SslContextUtil.loadCredentials(keyStoreFilePath, keyAlias, keyStorePassword.toCharArray(), - keyPassword.toCharArray()); - } catch (GeneralSecurityException | IOException e) { - throw new RuntimeException("Failed to load serverCredentials due to: ", e); - } - } - private InetSocketAddress getInetSocketAddress() throws UnknownHostException { InetAddress addr = InetAddress.getByName(host); return new InetSocketAddress(addr, port); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java index 754476bc26..b354b98bdb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java @@ -27,6 +27,30 @@ import java.net.URL; @Slf4j public class ResourceUtils { + public static boolean resourceExists(Object classLoaderSource, String filePath) { + return resourceExists(classLoaderSource.getClass().getClassLoader(), filePath); + } + + public static boolean resourceExists(ClassLoader classLoader, String filePath) { + File resourceFile = new File(filePath); + if (resourceFile.exists()) { + return true; + } else { + InputStream classPathStream = classLoader.getResourceAsStream(filePath); + if (classPathStream != null) { + return true; + } else { + try { + URL url = Resources.getResource(filePath); + if (url != null) { + return true; + } + } catch (IllegalArgumentException e) {} + } + } + return false; + } + public static InputStream getInputStream(Object classLoaderSource, String filePath) { return getInputStream(classLoaderSource.getClass().getClassLoader(), filePath); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 16f9443547..0ea9be4388 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -27,6 +27,7 @@ import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigurationAdapter; @@ -114,49 +115,22 @@ public class LwM2MTransportBootstrapService { } private void setServerWithCredentials(LeshanBootstrapServerBuilder builder) { - try { - if (serverConfig.getKeyStoreValue() != null) { - KeyStore keyStoreServer = serverConfig.getKeyStoreValue(); - if (this.setBuilderX509(builder)) { - X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(serverConfig.getRootCertificateAlias()); - if (rootCAX509Cert != null) { - X509Certificate[] trustedCertificates = new X509Certificate[1]; - trustedCertificates[0] = rootCAX509Cert; - builder.setTrustedCertificates(trustedCertificates); - } else { - /* by default trust all */ - builder.setTrustedCertificates(new X509Certificate[0]); - } - } + if (this.bootstrapConfig.getSslCredentials() != null) { + SslCredentials sslCredentials = this.bootstrapConfig.getSslCredentials(); + builder.setPublicKey(sslCredentials.getPublicKey()); + builder.setPrivateKey(sslCredentials.getPrivateKey()); + builder.setCertificateChain(sslCredentials.getCertificateChain()); + if (this.serverConfig.getTrustSslCredentials() != null) { + builder.setTrustedCertificates(this.serverConfig.getTrustSslCredentials().getTrustedCertificates()); } else { /* by default trust all */ builder.setTrustedCertificates(new X509Certificate[0]); - log.info("Unable to load X509 files for BootStrapServer"); - this.pskMode = true; } - } catch (KeyStoreException ex) { - log.error("[{}] Unable to load X509 files server", ex.getMessage()); + } else { + /* by default trust all */ + builder.setTrustedCertificates(new X509Certificate[0]); + log.info("Unable to load X509 files for BootStrapServer"); + this.pskMode = true; } } - - private boolean setBuilderX509(LeshanBootstrapServerBuilder builder) { - try { - X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(serverConfig.getKeyStoreValue().getCertificateChain(this.bootstrapConfig.getCertificateAlias())); - X509Certificate serverCertificate = certificateChain[0]; - PrivateKey privateKey = (PrivateKey) serverConfig.getKeyStoreValue().getKey(this.bootstrapConfig.getCertificateAlias(), serverConfig.getCertificatePassword() == null ? null : serverConfig.getCertificatePassword().toCharArray()); - PublicKey publicKey = serverCertificate.getPublicKey(); - if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) { - builder.setPublicKey(serverCertificate.getPublicKey()); - builder.setPrivateKey(privateKey); - builder.setCertificateChain(certificateChain); - return true; - } else { - return false; - } - } catch (Exception ex) { - log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); - return false; - } - } - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MSecureServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MSecureServerConfig.java index a525c5f157..b8a4f2c976 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MSecureServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MSecureServerConfig.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.transport.lwm2m.config; +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; + public interface LwM2MSecureServerConfig { Integer getId(); @@ -27,8 +29,6 @@ public interface LwM2MSecureServerConfig { Integer getSecurePort(); - String getCertificateAlias(); - - String getCertificatePassword(); + SslCredentials getSslCredentials(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java index 0806ef9e90..749f7352ba 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java @@ -17,9 +17,15 @@ package org.thingsboard.server.transport.lwm2m.config; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; +import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; @Slf4j @Component @@ -46,12 +52,18 @@ public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig { @Value("${transport.lwm2m.bootstrap.security.bind_port:}") private Integer securePort; - @Getter - @Value("${transport.lwm2m.bootstrap.security.key_alias:}") - private String certificateAlias; + @Bean + @ConfigurationProperties(prefix = "transport.lwm2m.bootstrap.security.credentials") + public SslCredentialsConfig lwm2mBootstrapCredentials() { + return new SslCredentialsConfig("LWM2M Bootstrap DTLS Credentials", false); + } - @Getter - @Value("${transport.lwm2m.bootstrap.security.key_password:}") - private String certificatePassword; + @Autowired + @Qualifier("lwm2mBootstrapCredentials") + private SslCredentialsConfig credentialsConfig; + @Override + public SslCredentials getSslCredentials() { + return this.credentialsConfig.getCredentials(); + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index bde8741f3b..f444b74c2b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -18,10 +18,16 @@ package org.thingsboard.server.transport.lwm2m.config; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.ResourceUtils; +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; +import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; import javax.annotation.PostConstruct; import java.io.InputStream; @@ -64,26 +70,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Value("${transport.lwm2m.clean_period_in_sec:}") private int cleanPeriodInSec; - @Getter - @Value("${transport.lwm2m.security.key_store_type:}") - private String keyStoreType; - - @Getter - @Value("${transport.lwm2m.security.key_store:}") - private String keyStoreFilePath; - - @Getter - @Setter - private KeyStore keyStoreValue; - - @Getter - @Value("${transport.lwm2m.security.key_store_password:}") - private String keyStorePassword; - - @Getter - @Value("${transport.lwm2m.security.root_alias:}") - private String rootCertificateAlias; - @Getter @Value("${transport.lwm2m.server.id:}") private Integer id; @@ -104,14 +90,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Value("${transport.lwm2m.server.security.bind_port:}") private Integer securePort; - @Getter - @Value("${transport.lwm2m.server.security.key_alias:}") - private String certificateAlias; - - @Getter - @Value("${transport.lwm2m.server.security.key_password:}") - private String certificatePassword; - @Getter @Value("${transport.lwm2m.log_max_length:}") private int logMaxLength; @@ -124,15 +102,32 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Value("${transport.lwm2m.paging_transmission_window:10000}") private long pagingTransmissionWindow; - @PostConstruct - public void init() { - try { - InputStream keyStoreInputStream = ResourceUtils.getInputStream(this, keyStoreFilePath); - keyStoreValue = KeyStore.getInstance(keyStoreType); - keyStoreValue.load(keyStoreInputStream, keyStorePassword == null ? null : keyStorePassword.toCharArray()); - } catch (Exception e) { - log.info("Unable to lookup LwM2M keystore. Reason: {}, {}", keyStoreFilePath, e.getMessage()); - } + @Bean + @ConfigurationProperties(prefix = "transport.lwm2m.server.security.credentials") + public SslCredentialsConfig lwm2mServerCredentials() { + return new SslCredentialsConfig("LWM2M Server DTLS Credentials", false); + } + + @Autowired + @Qualifier("lwm2mServerCredentials") + private SslCredentialsConfig credentialsConfig; + + @Bean + @ConfigurationProperties(prefix = "transport.lwm2m.security.trust-credentials") + public SslCredentialsConfig lwm2mTrustCredentials() { + return new SslCredentialsConfig("LWM2M Trust Credentials", true); } + @Autowired + @Qualifier("lwm2mTrustCredentials") + private SslCredentialsConfig trustCredentialsConfig; + + @Override + public SslCredentials getSslCredentials() { + return this.credentialsConfig.getCredentials(); + } + + public SslCredentials getTrustSslCredentials() { + return this.trustCredentialsConfig.getCredentials(); + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index fe04410c17..1837093e8c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -87,12 +87,8 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer try { /* by default trust all */ X509Certificate[] trustedCertificates = new X509Certificate[0]; - if (config.getKeyStoreValue() != null) { - X509Certificate rootCAX509Cert = (X509Certificate) config.getKeyStoreValue().getCertificate(config.getRootCertificateAlias()); - if (rootCAX509Cert != null) { - trustedCertificates = new X509Certificate[1]; - trustedCertificates[0] = rootCAX509Cert; - } + if (config.getTrustSslCredentials() != null) { + trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates(); } staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates); } catch (Exception e) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index 5a02f3b194..3efc71b5fe 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -29,6 +29,7 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.springframework.stereotype.Component; import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; @@ -141,7 +142,11 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { } private void setServerWithCredentials(LeshanServerBuilder builder, DtlsConnectorConfig.Builder dtlsConfig) { - if (config.getKeyStoreValue() != null && this.setBuilderX509(builder)) { + if (this.config.getSslCredentials() != null) { + SslCredentials sslCredentials = this.config.getSslCredentials(); + builder.setPublicKey(sslCredentials.getPublicKey()); + builder.setPrivateKey(sslCredentials.getPrivateKey()); + builder.setCertificateChain(sslCredentials.getCertificateChain()); dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); builder.setAuthorizer(authorizer); dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); @@ -153,26 +158,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { } } - private boolean setBuilderX509(LeshanServerBuilder builder) { - try { - X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(config.getKeyStoreValue().getCertificateChain(config.getCertificateAlias())); - X509Certificate serverCertificate = certificateChain[0]; - PrivateKey privateKey = (PrivateKey) config.getKeyStoreValue().getKey(config.getCertificateAlias(), config.getCertificatePassword() == null ? null : config.getCertificatePassword().toCharArray()); - PublicKey publicKey = serverCertificate.getPublicKey(); - if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) { - builder.setPublicKey(serverCertificate.getPublicKey()); - builder.setPrivateKey(privateKey); - builder.setCertificateChain(certificateChain); - return true; - } else { - return false; - } - } catch (Exception ex) { - log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); - return false; - } - } - @Override public String getName() { return DataConstants.LWM2M_TRANSPORT_NAME; diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java index fad743aec2..215aef408c 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java @@ -18,16 +18,20 @@ package org.thingsboard.server.transport.mqtt; import io.netty.handler.ssl.SslHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; +import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.gen.transport.TransportProtos; @@ -38,8 +42,6 @@ import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -import java.io.InputStream; -import java.security.KeyStore; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -56,18 +58,20 @@ public class MqttSslHandlerProvider { @Value("${transport.mqtt.ssl.protocol}") private String sslProtocol; - @Value("${transport.mqtt.ssl.key_store}") - private String keyStoreFile; - @Value("${transport.mqtt.ssl.key_store_password}") - private String keyStorePassword; - @Value("${transport.mqtt.ssl.key_password}") - private String keyPassword; - @Value("${transport.mqtt.ssl.key_store_type}") - private String keyStoreType; @Autowired private TransportService transportService; + @Bean + @ConfigurationProperties(prefix = "transport.mqtt.ssl.credentials") + public SslCredentialsConfig mqttSslCredentials() { + return new SslCredentialsConfig("MQTT SSL Credentials", false); + } + + @Autowired + @Qualifier("mqttSslCredentials") + private SslCredentialsConfig mqttSslCredentialsConfig; + private SSLContext sslContext; public SslHandler getSslHandler() { @@ -86,19 +90,9 @@ public class MqttSslHandlerProvider { private SSLContext createSslContext() { try { - TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - KeyStore trustStore = KeyStore.getInstance(keyStoreType); - try (InputStream tsFileInputStream = ResourceUtils.getInputStream(this, keyStoreFile)) { - trustStore.load(tsFileInputStream, keyStorePassword.toCharArray()); - } - tmFactory.init(trustStore); - - KeyStore ks = KeyStore.getInstance(keyStoreType); - try (InputStream ksFileInputStream = ResourceUtils.getInputStream(this, keyStoreFile)) { - ks.load(ksFileInputStream, keyStorePassword.toCharArray()); - } - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(ks, keyPassword.toCharArray()); + SslCredentials sslCredentials = this.mqttSslCredentialsConfig.getCredentials(); + TrustManagerFactory tmFactory = sslCredentials.createTrustManagerFactory(); + KeyManagerFactory kmf = sslCredentials.createKeyManagerFactory(); KeyManager[] km = kmf.getKeyManagers(); TrustManager x509wrapped = getX509TrustManager(tmFactory); diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index fad019a1b5..b66676e61c 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -129,6 +129,14 @@ org.eclipse.leshan leshan-server-cf + + org.bouncycastle + bcprov-jdk15on + + + org.bouncycastle + bcpkix-jdk15on + diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java new file mode 100644 index 0000000000..04dafc56fd --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java @@ -0,0 +1,191 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.config.ssl; + +import org.thingsboard.server.common.data.StringUtils; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStore.PrivateKeyEntry; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableEntryException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +public abstract class AbstractSslCredentials implements SslCredentials { + + private char[] keyPasswordArray; + + private KeyStore keyStore; + + private PrivateKey privateKey; + + private PublicKey publicKey; + + private X509Certificate[] chain; + + private X509Certificate[] trusts; + + @Override + public void init(boolean trustsOnly) throws IOException, GeneralSecurityException { + String keyPassword = getKeyPassword(); + if (StringUtils.isEmpty(keyPassword)) { + this.keyPasswordArray = new char[0]; + } else { + this.keyPasswordArray = keyPassword.toCharArray(); + } + this.keyStore = this.loadKeyStore(trustsOnly, this.keyPasswordArray); + Set trustedCerts = getTrustedCerts(this.keyStore); + this.trusts = trustedCerts.toArray(new X509Certificate[0]); + if (!trustsOnly) { + PrivateKeyEntry privateKeyEntry = null; + String keyAlias = this.getKeyAlias(); + if (!StringUtils.isEmpty(keyAlias)) { + privateKeyEntry = tryGetPrivateKeyEntry(this.keyStore, keyAlias, this.keyPasswordArray); + } else { + for (Enumeration e = this.keyStore.aliases(); e.hasMoreElements(); ) { + String alias = e.nextElement(); + privateKeyEntry = tryGetPrivateKeyEntry(this.keyStore, alias, this.keyPasswordArray); + if (privateKeyEntry != null) { + break; + } + } + } + if (privateKeyEntry == null) { + throw new IllegalArgumentException("Failed to get private key from the keystore or pem files. " + + "Please check if the private key exists in the keystore or pem files and if the provided private key password is valid."); + } + this.chain = asX509Certificates(privateKeyEntry.getCertificateChain()); + this.privateKey = privateKeyEntry.getPrivateKey(); + if (this.chain.length > 0) { + this.publicKey = this.chain[0].getPublicKey(); + } + } + } + + @Override + public PrivateKey getPrivateKey() { + return this.privateKey; + } + + @Override + public PublicKey getPublicKey() { + return this.publicKey; + } + + @Override + public X509Certificate[] getCertificateChain() { + return this.chain; + } + + @Override + public X509Certificate[] getTrustedCertificates() { + return this.trusts; + } + + @Override + public TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException { + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmFactory.init(this.keyStore); + return tmFactory; + } + + @Override + public KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException { + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(this.keyStore, this.keyPasswordArray); + return kmf; + } + + protected abstract boolean canUse(); + + protected abstract String getKeyPassword(); + + protected abstract String getKeyAlias(); + + protected abstract KeyStore loadKeyStore(boolean isPrivateKeyRequired, char[] keyPasswordArray) throws IOException, GeneralSecurityException; + + private static X509Certificate[] asX509Certificates(Certificate[] certificates) { + if (null == certificates || 0 == certificates.length) { + throw new IllegalArgumentException("certificates missing!"); + } + X509Certificate[] x509Certificates = new X509Certificate[certificates.length]; + for (int index = 0; certificates.length > index; ++index) { + if (null == certificates[index]) { + throw new IllegalArgumentException("[" + index + "] is null!"); + } + try { + x509Certificates[index] = (X509Certificate) certificates[index]; + } catch (ClassCastException e) { + throw new IllegalArgumentException("[" + index + "] is not a x509 certificate! Instead it's a " + + certificates[index].getClass().getName()); + } + } + return x509Certificates; + } + + private static PrivateKeyEntry tryGetPrivateKeyEntry(KeyStore keyStore, String alias, char[] pwd) { + PrivateKeyEntry entry = null; + try { + if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) { + try { + entry = (KeyStore.PrivateKeyEntry) keyStore + .getEntry(alias, new KeyStore.PasswordProtection(pwd)); + } catch (UnsupportedOperationException e) { + PrivateKey key = (PrivateKey) keyStore.getKey(alias, pwd); + Certificate[] certs = keyStore.getCertificateChain(alias); + entry = new KeyStore.PrivateKeyEntry(key, certs); + } + } + } catch (KeyStoreException | UnrecoverableEntryException | NoSuchAlgorithmException ignored) {} + return entry; + } + + private static Set getTrustedCerts(KeyStore ks) { + Set set = new HashSet<>(); + try { + for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) { + String alias = e.nextElement(); + if (ks.isCertificateEntry(alias)) { + Certificate cert = ks.getCertificate(alias); + if (cert instanceof X509Certificate) { + set.add((X509Certificate)cert); + } + } else if (ks.isKeyEntry(alias)) { + Certificate[] certs = ks.getCertificateChain(alias); + if ((certs != null) && (certs.length > 0) && + (certs[0] instanceof X509Certificate)) { + set.add((X509Certificate)certs[0]); + } + } + } + } catch (KeyStoreException ignored) {} + return Collections.unmodifiableSet(set); + } + + +} diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java new file mode 100644 index 0000000000..56f4009b0d --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java @@ -0,0 +1,52 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.config.ssl; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.thingsboard.server.common.data.ResourceUtils; +import org.thingsboard.server.common.data.StringUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.KeyStore; + +@Data +@EqualsAndHashCode(callSuper = false) +public class KeystoreSslCredentials extends AbstractSslCredentials { + + private String type; + private String storeFile; + private String storePassword; + private String keyPassword; + private String keyAlias; + + @Override + protected boolean canUse() { + return ResourceUtils.resourceExists(this, this.storeFile); + } + + @Override + protected KeyStore loadKeyStore(boolean trustsOnly, char[] keyPasswordArray) throws IOException, GeneralSecurityException { + String keyStoreType = StringUtils.isEmpty(this.type) ? KeyStore.getDefaultType() : this.type; + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + try (InputStream tsFileInputStream = ResourceUtils.getInputStream(this, this.storeFile)) { + keyStore.load(tsFileInputStream, StringUtils.isEmpty(this.storePassword) ? new char[0] : this.storePassword.toCharArray()); + } + return keyStore; + } +} diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java new file mode 100644 index 0000000000..0575d68149 --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java @@ -0,0 +1,130 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.config.ssl; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMDecryptorProvider; +import org.bouncycastle.openssl.PEMEncryptedKeyPair; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; +import org.thingsboard.server.common.data.ResourceUtils; +import org.thingsboard.server.common.data.StringUtils; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Data +@EqualsAndHashCode(callSuper = false) +public class PemSslCredentials extends AbstractSslCredentials { + + private String certFile; + private String keyFile; + private String keyPassword; + private final String keyAlias = "serveralias"; + + @Override + protected boolean canUse() { + return ResourceUtils.resourceExists(this, this.certFile); + } + + @Override + protected KeyStore loadKeyStore(boolean trustsOnly, char[] keyPasswordArray) throws IOException, GeneralSecurityException { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + List certificates = new ArrayList<>(); + PrivateKey privateKey = null; + JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); + try (InputStream inStream = ResourceUtils.getInputStream(this, this.certFile)) { + try (PEMParser pemParser = new PEMParser(new InputStreamReader(inStream))) { + Object object; + while((object = pemParser.readObject()) != null) { + if (object instanceof X509CertificateHolder) { + X509Certificate x509Cert = certConverter.getCertificate((X509CertificateHolder) object); + certificates.add(x509Cert); + } else if (object instanceof PEMEncryptedKeyPair) { + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(keyPasswordArray); + privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); + } else if (object instanceof PEMKeyPair) { + privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); + } else if (object instanceof PrivateKeyInfo) { + privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); + } + } + } + } + if (privateKey == null && !StringUtils.isEmpty(this.keyFile)) { + if (ResourceUtils.resourceExists(this, this.keyFile)) { + try (InputStream inStream = ResourceUtils.getInputStream(this, this.keyFile)) { + try (PEMParser pemParser = new PEMParser(new InputStreamReader(inStream))) { + Object object; + while ((object = pemParser.readObject()) != null) { + if (object instanceof PEMEncryptedKeyPair) { + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(keyPasswordArray); + privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); + break; + } else if (object instanceof PEMKeyPair) { + privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); + break; + } else if (object instanceof PrivateKeyInfo) { + privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); + } + } + } + } + } + } + if (certificates.isEmpty()) { + throw new IllegalArgumentException("No certificates found in certFile: " + this.certFile); + } + if (privateKey == null && !trustsOnly) { + throw new IllegalArgumentException("Unable to load private key neither from certFile: " + this.certFile + " nor from keyFile: " + this.keyFile); + } + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null); + List unique = certificates.stream().distinct().collect(Collectors.toList()); + for (int i = 0; i < unique.size(); i++) { + keyStore.setCertificateEntry("root-" + i, unique.get(i)); + } + if (privateKey != null) { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + CertPath certPath = factory.generateCertPath(certificates); + List path = certPath.getCertificates(); + Certificate[] x509Certificates = path.toArray(new Certificate[0]); + keyStore.setKeyEntry(this.keyAlias, privateKey, keyPasswordArray, x509Certificates); + } + return keyStore; + } +} diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java new file mode 100644 index 0000000000..ef412815d7 --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.config.ssl; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.X509Certificate; + +public interface SslCredentials { + + void init(boolean trustsOnly) throws IOException, GeneralSecurityException; + + PrivateKey getPrivateKey(); + + PublicKey getPublicKey(); + + X509Certificate[] getCertificateChain(); + + X509Certificate[] getTrustedCertificates(); + + TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException; + + KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException; + +} diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsConfig.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsConfig.java new file mode 100644 index 0000000000..8b43f36574 --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsConfig.java @@ -0,0 +1,66 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.config.ssl; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.PostConstruct; + +@Slf4j +@Data +public class SslCredentialsConfig { + + private boolean enabled = true; + private SslCredentialsType type; + private PemSslCredentials pem; + private KeystoreSslCredentials keystore; + + private SslCredentials credentials; + + private final String name; + private final boolean trustsOnly; + + public SslCredentialsConfig(String name, boolean trustsOnly) { + this.name = name; + this.trustsOnly = trustsOnly; + } + + @PostConstruct + public void init() { + if (this.enabled) { + log.info("{}: Initializing SSL credentials.", name); + if (SslCredentialsType.PEM.equals(type) && pem.canUse()) { + this.credentials = this.pem; + } else if (keystore.canUse()) { + if (SslCredentialsType.PEM.equals(type)) { + log.warn("{}: Specified PEM configuration is not valid. Using SSL keystore configuration as fallback.", name); + } + this.credentials = this.keystore; + } else { + throw new RuntimeException(name + ": Invalid SSL credentials configuration. None of the PEM or KEYSTORE configurations can be used!"); + } + try { + this.credentials.init(this.trustsOnly); + } catch (Exception e) { + throw new RuntimeException(name + ": Failed to init SSL credentials configuration.", e); + } + } else { + log.info("{}: Skipping initialization of disabled SSL credentials.", name); + } + } + +} diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsType.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsType.java new file mode 100644 index 0000000000..64115e57b6 --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsType.java @@ -0,0 +1,21 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.config.ssl; + +public enum SslCredentialsType { + PEM, + KEYSTORE +} diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 9aab46b824..adaffed7de 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -98,17 +98,33 @@ transport: bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" # CoAP DTLS bind port bind_port: "${COAP_DTLS_BIND_PORT:5684}" - # Path to the key store that holds the certificate - key_store: "${COAP_DTLS_KEY_STORE:coapserver.jks}" - # Password used to access the key store - key_store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" - # Key alias - key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}" - # Skip certificate validity check for client certificates. - skip_validity_check_for_client_cert: "${COAP_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" + # Server DTLS credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${COAP_DTLS_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}" + # Path to the server certificate private key file (optional) + key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}" + # Server certificate private key password (optional) + key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${COAP_DTLS_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the SSL certificate + store_file: "${COAP_DTLS_KEY_STORE:coapserver.jks}" + # Password used to access the key store + store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" + # Key alias + key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}" x509: + # Skip certificate validity check for client certificates. + skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}" dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" sessions: diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 4280ccb1af..be5bb62a00 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -111,9 +111,33 @@ transport: security: bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}" + # Server X509 Certificates support + credentials: + # Whether to enable LWM2M server X509 Certificate/RPK support + enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}" + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}" + # Path to the server certificate private key file (optional) + key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}" + # Server certificate private key password (optional) + key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${LWM2M_SERVER_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the SSL certificate + store_file: "${LWM2M_SERVER_KEY_STORE:lwm2mserver.jks}" + # Password used to access the key store + store_password: "${LWM2M_SERVER_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_key_password}" + # Key alias + key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" # Only Certificate_x509: - key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" - key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}" skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" bootstrap: enable: "${LWM2M_ENABLED_BS:true}" @@ -123,18 +147,51 @@ transport: security: bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}" - # Only Certificate_x509: - key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}" - key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}" + # Bootstrap server X509 Certificates support + credentials: + # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support + enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}" + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}" + # Path to the server certificate private key file (optional) + key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}" + # Server certificate private key password (optional) + key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${LWM2M_BS_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the SSL certificate + store_file: "${LWM2M_BS_KEY_STORE:lwm2mserver.jks}" + # Password used to access the key store + store_password: "${LWM2M_BS_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${LWM2M_BS_KEY_PASSWORD:server_key_password}" + # Key alias + key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}" security: - # Certificate_x509: - # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format - # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh - key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" - # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks" - key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}" - key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}" - root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}" + # X509 trust certificates + trust-credentials: + # Whether to load X509 trust certificates + enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}" + # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore) + type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}" + # PEM certificates + pem: + # Path to the certificates file (holds trust certificates) + cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mserver.pem}" + # Keystore with trust certificates + keystore: + # Type of the key store + type: "${LWM2M_TRUST_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the X509 certificates + store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mserver.jks}" + # Password used to access the key store + store_password: "${LWM2M_TRUST_KEY_STORE_PASSWORD:server_ks_password}" recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" timeout: "${LWM2M_TIMEOUT:120000}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index e0d0144d84..75538e6f61 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -106,14 +106,28 @@ transport: bind_port: "${MQTT_SSL_BIND_PORT:8883}" # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}" - # Path to the key store that holds the SSL certificate - key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" - # Password used to access the key store - key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" - # Type of the key store - key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${MQTT_SSL_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}" + # Path to the server certificate private key file (optional) + key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}" + # Server certificate private key password (optional) + key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}" + # Path to the key store that holds the SSL certificate + store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" + # Password used to access the key store + store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" sessions: From 706ace25ad585a7294ecd30858153b94627d1970 Mon Sep 17 00:00:00 2001 From: Artem Babak Date: Tue, 26 Oct 2021 21:52:35 +0300 Subject: [PATCH 145/303] Protobuf editor implementation --- ...ile-transport-configuration.component.html | 20 +++---- ...ofile-transport-configuration.component.ts | 21 +++++++ .../protobuf-content.component.html | 6 +- .../protobuf-content.component.scss | 3 +- .../components/protobuf-content.component.ts | 58 +++++-------------- 5 files changed, 47 insertions(+), 61 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html index 8e7d082ad2..f12af60efc 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html @@ -74,9 +74,8 @@
    -
    + {{ 'device-profile.telemetry-proto-schema-required' | translate}} -
    -
    + + {{ 'device-profile.attributes-proto-schema-required' | translate}} -
    -
    + + {{ 'device-profile.rpc-request-proto-required' | translate}} -
    -
    + + {{ 'device-profile.rpc-response-proto-schema-required' | translate}} -
    +
    diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts index 5254b7574f..c5ecc8371a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts @@ -56,6 +56,10 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control transportPayloadTypes = Object.keys(TransportPayloadType); + get protobufControls() { + return this.getProtobufControls(); + } + transportPayloadTypeTranslations = transportPayloadTypeTranslationMap; mqttDeviceProfileTransportConfigurationFormGroup: FormGroup; @@ -211,4 +215,21 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control } return null; } + + getProtobufControls() { + return [ + { + name: 'deviceAttributesProtoSchema', + label: 'device-profile.attributes-proto-schema', + errorControl: 'transportPayloadTypeConfiguration.deviceAttributesProtoSchema', + errorText: 'device-profile.attributes-proto-schema-required' + }, + { + deviceTelemetryProtoSchema: 'deviceRpcRequestProtoSchema', + label: 'device-profile.rpc-request-proto-schema', + errorControl: 'transportPayloadTypeConfiguration.deviceRpcRequestProtoSchema', + errorText: 'device-profile.rpc-request-proto-required' + } + ]; + } } diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.html b/ui-ngx/src/app/shared/components/protobuf-content.component.html index 43765c66d7..450c17e84b 100644 --- a/ui-ngx/src/app/shared/components/protobuf-content.component.html +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.html @@ -5,13 +5,9 @@ -
    = { - mode: `ace/mode/${mode}`, + mode: `ace/mode/protobuf`, showGutter: true, showPrintMargin: false, readOnly: this.disabled || this.readonly, @@ -100,8 +95,7 @@ export class ProtobufContentComponent implements OnInit, ControlValueAccessor, V const advancedOptions = { enableSnippets: true, enableBasicAutocompletion: true, - enableLiveAutocompletion: true, - autoScrollEditorIntoView: true + enableLiveAutocompletion: true }; editorOptions = {...editorOptions, ...advancedOptions}; @@ -130,31 +124,6 @@ export class ProtobufContentComponent implements OnInit, ControlValueAccessor, V } } - private onAceEditorResize() { - if (this.editorsResizeCaf) { - this.editorsResizeCaf(); - this.editorsResizeCaf = null; - } - this.editorsResizeCaf = this.raf.raf(() => { - this.protobufEditor.resize(); - this.protobufEditor.renderer.updateFull(); - }); - } - - ngOnChanges(changes: SimpleChanges): void { - for (const propName of Object.keys(changes)) { - const change = changes[propName]; - if (!change.firstChange && change.currentValue !== change.previousValue) { - if (propName === 'contentType') { - if (this.protobufEditor) { - let mode = 'protobuf'; - this.protobufEditor.session.setMode(`ace/mode/${mode}`); - } - } - } - } - } - registerOnChange(fn: any): void { this.propagateChange = fn; } @@ -169,7 +138,7 @@ export class ProtobufContentComponent implements OnInit, ControlValueAccessor, V } } - public validate(c: FormControl) { + validate(c: FormControl) { return (this.contentValid) ? null : { contentBody: { valid: false, @@ -195,7 +164,7 @@ export class ProtobufContentComponent implements OnInit, ControlValueAccessor, V } } - beautifyJSON() { + beautifyProtobuf() { beautifyJs(this.contentBody, {indent_size: 4, wrap_line_length: 60}).subscribe( (res) => { this.protobufEditor.setValue(res ? res : '', -1); @@ -204,12 +173,6 @@ export class ProtobufContentComponent implements OnInit, ControlValueAccessor, V ); } - minifyJSON() { - const res = JSON.stringify(this.contentBody); - this.protobufEditor.setValue(res ? res : '', -1); - this.updateView(); - } - onFullscreen() { if (this.protobufEditor) { setTimeout(() => { @@ -218,4 +181,15 @@ export class ProtobufContentComponent implements OnInit, ControlValueAccessor, V } } + private onAceEditorResize() { + if (this.editorsResizeCaf) { + this.editorsResizeCaf(); + this.editorsResizeCaf = null; + } + this.editorsResizeCaf = this.raf.raf(() => { + this.protobufEditor.resize(); + this.protobufEditor.renderer.updateFull(); + }); + } + } From bc488421a199f79caf8ac09b9fa51a5291cd743a Mon Sep 17 00:00:00 2001 From: Artem Babak Date: Tue, 26 Oct 2021 22:06:48 +0300 Subject: [PATCH 146/303] Protobuf component: removed validation --- ...ofile-transport-configuration.component.ts | 21 ------------------ .../protobuf-content.component.html | 2 +- .../components/protobuf-content.component.ts | 22 ++----------------- 3 files changed, 3 insertions(+), 42 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts index c5ecc8371a..5254b7574f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts @@ -56,10 +56,6 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control transportPayloadTypes = Object.keys(TransportPayloadType); - get protobufControls() { - return this.getProtobufControls(); - } - transportPayloadTypeTranslations = transportPayloadTypeTranslationMap; mqttDeviceProfileTransportConfigurationFormGroup: FormGroup; @@ -215,21 +211,4 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control } return null; } - - getProtobufControls() { - return [ - { - name: 'deviceAttributesProtoSchema', - label: 'device-profile.attributes-proto-schema', - errorControl: 'transportPayloadTypeConfiguration.deviceAttributesProtoSchema', - errorText: 'device-profile.attributes-proto-schema-required' - }, - { - deviceTelemetryProtoSchema: 'deviceRpcRequestProtoSchema', - label: 'device-profile.rpc-request-proto-schema', - errorControl: 'transportPayloadTypeConfiguration.deviceRpcRequestProtoSchema', - errorText: 'device-profile.rpc-request-proto-required' - } - ]; - } } diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.html b/ui-ngx/src/app/shared/components/protobuf-content.component.html index 450c17e84b..b1ec6c8dd4 100644 --- a/ui-ngx/src/app/shared/components/protobuf-content.component.html +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.html @@ -2,7 +2,7 @@ tb-fullscreen [fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column">
    - +
    diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html index f12af60efc..d57783f17c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html @@ -104,7 +104,7 @@ [fillHeight]="true"> - {{ 'device-profile.rpc-request-proto-required' | translate}} + {{ 'device-profile.rpc-request-proto-schema-required' | translate}} diff --git a/ui-ngx/src/app/shared/models/ace/ace.models.ts b/ui-ngx/src/app/shared/models/ace/ace.models.ts index c9136b8e79..9a3c30766e 100644 --- a/ui-ngx/src/app/shared/models/ace/ace.models.ts +++ b/ui-ngx/src/app/shared/models/ace/ace.models.ts @@ -36,6 +36,7 @@ export function loadAceDependencies(): Observable { aceObservables.push(from(import('ace-builds/src-noconflict/mode-text'))); aceObservables.push(from(import('ace-builds/src-noconflict/mode-markdown'))); aceObservables.push(from(import('ace-builds/src-noconflict/mode-html'))); + aceObservables.push(from(import('ace-builds/src-noconflict/mode-c_cpp'))); aceObservables.push(from(import('ace-builds/src-noconflict/mode-protobuf'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/java'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/css'))); @@ -44,6 +45,8 @@ export function loadAceDependencies(): Observable { aceObservables.push(from(import('ace-builds/src-noconflict/snippets/text'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/markdown'))); aceObservables.push(from(import('ace-builds/src-noconflict/snippets/html'))); + aceObservables.push(from(import('ace-builds/src-noconflict/snippets/c_cpp'))); + aceObservables.push(from(import('ace-builds/src-noconflict/snippets/protobuf'))); aceObservables.push(from(import('ace-builds/src-noconflict/theme-textmate'))); aceObservables.push(from(import('ace-builds/src-noconflict/theme-github'))); return forkJoin(aceObservables).pipe( From 3471a54f8bb89875792f6defb0f363ae97535631 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Wed, 27 Oct 2021 11:23:06 +0300 Subject: [PATCH 151/303] Extend height of protobuf editor to 10 lines --- .../src/app/shared/components/protobuf-content.component.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.scss b/ui-ngx/src/app/shared/components/protobuf-content.component.scss index 0e44e2373d..b2ebc9bbe6 100644 --- a/ui-ngx/src/app/shared/components/protobuf-content.component.scss +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.scss @@ -32,7 +32,7 @@ #tb-protobuf-input { width: 100%; min-width: 200px; - min-height: 100px; + min-height: 160px; height: 100%; &:not(.fill-height) { From 0745ee3d0a70ad732627027fcda466e93d431fbe Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Wed, 27 Oct 2021 11:26:46 +0300 Subject: [PATCH 152/303] fixed passed topic name for consumer constructor in rule engine queue --- application/src/main/resources/thingsboard.yml | 7 ++++++- .../server/queue/provider/AwsSqsMonolithQueueFactory.java | 2 +- .../queue/provider/AwsSqsTbRuleEngineQueueFactory.java | 2 +- .../queue/provider/InMemoryMonolithQueueFactory.java | 2 +- .../server/queue/provider/KafkaMonolithQueueFactory.java | 2 +- .../queue/provider/KafkaTbRuleEngineQueueFactory.java | 2 +- .../server/queue/provider/PubSubMonolithQueueFactory.java | 2 +- .../queue/provider/PubSubTbRuleEngineQueueFactory.java | 2 +- .../queue/provider/RabbitMqMonolithQueueFactory.java | 2 +- .../queue/provider/RabbitMqTbRuleEngineQueueFactory.java | 2 +- .../queue/provider/ServiceBusMonolithQueueFactory.java | 2 +- .../queue/provider/ServiceBusTbRuleEngineQueueFactory.java | 2 +- 12 files changed, 17 insertions(+), 12 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index f88d5f297c..f307d95d1c 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -866,10 +866,15 @@ queue: sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" + # Key-value properties for Kafka consumer per specific topic, e.g. tb_ota_package is a topic name for ota, tb_rule_engine.sq is a topic name for default SequentialByOriginator queue. + # Check TB_QUEUE_CORE_OTA_TOPIC and TB_QUEUE_RE_SQ_TOPIC params consumer-properties-per-topic: tb_ota_package: - key: max.poll.records - value: 10 + value: "${TB_QUEUE_KAFKA_OTA_MAX_POLL_RECORDS:10}" +# tb_rule_engine.sq: +# - key: max.poll.records +# value: "${TB_QUEUE_KAFKA_SQ_MAX_POLL_RECORDS:1024}" other: # In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside - key: "request.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms value: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java index d89b03c744..026f879c8d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java @@ -117,7 +117,7 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new TbAwsSqsConsumerTemplate<>(ruleEngineAdmin, sqsSettings, ruleEngineSettings.getTopic(), + return new TbAwsSqsConsumerTemplate<>(ruleEngineAdmin, sqsSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java index 172f27d357..0e9f1812dd 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java @@ -109,7 +109,7 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new TbAwsSqsConsumerTemplate<>(ruleEngineAdmin, sqsSettings, ruleEngineSettings.getTopic(), + return new TbAwsSqsConsumerTemplate<>(ruleEngineAdmin, sqsSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java index cd1c34b612..81d2ba795a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java @@ -92,7 +92,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new InMemoryTbQueueConsumer<>(ruleEngineSettings.getTopic()); + return new InMemoryTbQueueConsumer<>(configuration.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java index 3bb0a53ad1..e08be485ea 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java @@ -160,7 +160,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi String queueName = configuration.getName(); TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); - consumerBuilder.topic(ruleEngineSettings.getTopic()); + consumerBuilder.topic(configuration.getTopic()); consumerBuilder.clientId("re-" + queueName + "-consumer-" + serviceInfoProvider.getServiceId() + "-" + consumerCount.incrementAndGet()); consumerBuilder.groupId("re-" + queueName + "-consumer"); consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java index fce429c9a3..58bc38d3a9 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java @@ -159,7 +159,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { String queueName = configuration.getName(); TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); - consumerBuilder.topic(ruleEngineSettings.getTopic()); + consumerBuilder.topic(configuration.getTopic()); consumerBuilder.clientId("re-" + queueName + "-consumer-" + serviceInfoProvider.getServiceId() + "-" + consumerCount.incrementAndGet()); consumerBuilder.groupId("re-" + queueName + "-consumer"); consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java index 3f014f578c..1d2f36c5c2 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java @@ -127,7 +127,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, ruleEngineSettings.getTopic(), + return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java index e82de20417..b02322496f 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java @@ -114,7 +114,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, ruleEngineSettings.getTopic(), + return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java index 7730f8f5dd..7d48803258 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java @@ -125,7 +125,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new TbRabbitMqConsumerTemplate<>(ruleEngineAdmin, rabbitMqSettings, ruleEngineSettings.getTopic(), + return new TbRabbitMqConsumerTemplate<>(ruleEngineAdmin, rabbitMqSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java index 09c0640fb8..2f8a3ed655 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java @@ -112,7 +112,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new TbRabbitMqConsumerTemplate<>(ruleEngineAdmin, rabbitMqSettings, ruleEngineSettings.getTopic(), + return new TbRabbitMqConsumerTemplate<>(ruleEngineAdmin, rabbitMqSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java index 2443093cf0..3731a56aee 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java @@ -124,7 +124,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new TbServiceBusConsumerTemplate<>(ruleEngineAdmin, serviceBusSettings, ruleEngineSettings.getTopic(), + return new TbServiceBusConsumerTemplate<>(ruleEngineAdmin, serviceBusSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java index 52858882cb..be11736ad2 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java @@ -112,7 +112,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { - return new TbServiceBusConsumerTemplate<>(ruleEngineAdmin, serviceBusSettings, ruleEngineSettings.getTopic(), + return new TbServiceBusConsumerTemplate<>(ruleEngineAdmin, serviceBusSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } From bb8f92b122231862647464eb8bc2939646df93c2 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 18 Oct 2021 11:22:39 +0300 Subject: [PATCH 153/303] fixed log typos in MqttTransportHandler --- .../server/transport/mqtt/MqttTransportHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 35e6e8c508..e9a962c9a2 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -995,7 +995,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onAttributeUpdate(UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg notification) { log.trace("[{}] Received attributes update notification to device", sessionId); - log.info("[{}] : attrSubTopicType: {}", notification.toString(), attrSubTopicType); String topic; MqttTransportAdaptor adaptor; switch (attrSubTopicType) { @@ -1031,7 +1030,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { - log.info("[{}] Received RPC command to device", sessionId); + log.trace("[{}] Received RPC command to device", sessionId); String baseTopic; MqttTransportAdaptor adaptor; switch (rpcSubTopicType) { From 09b75ac2e644a01aabb262b9bc320d428aa67807 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 27 Oct 2021 12:57:53 +0300 Subject: [PATCH 154/303] implementation updates after review --- .../transport/mqtt/MqttTransportHandler.java | 64 ++----------------- .../server/transport/mqtt/TopicType.java | 28 +++++++- .../BackwardCompatibilityAdaptor.java | 48 ++++++++++++-- .../mqtt/adaptors/MqttTransportAdaptor.java | 24 ++----- .../mqtt/session/DeviceSessionCtx.java | 18 +++--- .../assets/locale/locale.constant-en_US.json | 2 +- 6 files changed, 89 insertions(+), 95 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index a9534dd618..df88e94671 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -965,22 +965,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) { log.trace("[{}] Received get attributes response", sessionId); - String topicBase; + String topicBase = attrReqTopicType.getAttributesRequestTopicBase(); MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(attrReqTopicType); - switch (attrReqTopicType) { - case V2: - topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_TOPIC_PREFIX; - break; - case V2_JSON: - topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_JSON_TOPIC_PREFIX; - break; - case V2_PROTO: - topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_PROTO_TOPIC_PREFIX; - break; - default: - topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_TOPIC_PREFIX; - break; - } try { adaptor.convertToPublish(deviceSessionCtx, response, topicBase).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { @@ -991,22 +977,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onAttributeUpdate(UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg notification) { log.trace("[{}] Received attributes update notification to device", sessionId); - String topic; + String topic = attrSubTopicType.getAttributesSubTopic(); MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(attrSubTopicType); - switch (attrSubTopicType) { - case V2: - topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC; - break; - case V2_JSON: - topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC; - break; - case V2_PROTO: - topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC; - break; - default: - topic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC; - break; - } try { adaptor.convertToPublish(deviceSessionCtx, notification, topic).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { @@ -1023,22 +995,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { log.trace("[{}] Received RPC command to device", sessionId); - String baseTopic; + String baseTopic = rpcSubTopicType.getRpcRequestTopicBase(); MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(rpcSubTopicType); - switch (rpcSubTopicType) { - case V2: - baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_TOPIC; - break; - case V2_JSON: - baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_JSON_TOPIC; - break; - case V2_PROTO: - baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_PROTO_TOPIC; - break; - default: - baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_TOPIC; - break; - } try { adaptor.convertToPublish(deviceSessionCtx, rpcRequest, baseTopic).ifPresent(payload -> { int msgId = ((MqttPublishMessage) payload).variableHeader().packetId(); @@ -1075,22 +1033,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg rpcResponse) { log.trace("[{}] Received RPC response from server", sessionId); - String baseTopic; + String baseTopic = toServerRpcSubTopicType.getRpcResponseTopicBase(); MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(toServerRpcSubTopicType); - switch (toServerRpcSubTopicType) { - case V2: - baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_TOPIC; - break; - case V2_JSON: - baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_JSON_TOPIC; - break; - case V2_PROTO: - baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_PROTO_TOPIC; - break; - default: - baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_TOPIC; - break; - } try { adaptor.convertToPublish(deviceSessionCtx, rpcResponse, baseTopic).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TopicType.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TopicType.java index e2f427261e..45a0030772 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TopicType.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TopicType.java @@ -15,6 +15,32 @@ */ package org.thingsboard.server.transport.mqtt; +import lombok.Getter; +import org.thingsboard.server.common.data.device.profile.MqttTopics; + public enum TopicType { - V1, V2, V2_JSON, V2_PROTO + + V1(MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_TOPIC_PREFIX, MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_RPC_REQUESTS_TOPIC, MqttTopics.DEVICE_RPC_RESPONSE_TOPIC), + V2(MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_TOPIC_PREFIX, MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_TOPIC, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_TOPIC), + V2_JSON(MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_JSON_TOPIC_PREFIX, MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_JSON_TOPIC, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_JSON_TOPIC), + V2_PROTO(MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_PROTO_TOPIC_PREFIX, MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_PROTO_TOPIC); + + @Getter + private final String attributesRequestTopicBase; + + @Getter + private final String attributesSubTopic; + + @Getter + private final String rpcRequestTopicBase; + + @Getter + private final String rpcResponseTopicBase; + + TopicType(String attributesRequestTopicBase, String attributesSubTopic, String rpcRequestTopicBase, String rpcResponseTopicBase) { + this.attributesRequestTopicBase = attributesRequestTopicBase; + this.attributesSubTopic = attributesSubTopic; + this.rpcRequestTopicBase = rpcRequestTopicBase; + this.rpcResponseTopicBase = rpcResponseTopicBase; + } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java index 55733f7b81..a608d6c52d 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java @@ -40,7 +40,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToPostTelemetry(ctx, inbound); } catch (AdaptorException e) { - log.trace("failed to process post telemetry request msg: {} due to: ", inbound, e); + log.trace("[{}] failed to process post telemetry request msg: {} due to: ", ctx.getSessionId(), inbound, e); return jsonAdaptor.convertToPostTelemetry(ctx, inbound); } } @@ -50,7 +50,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToPostAttributes(ctx, inbound); } catch (AdaptorException e) { - log.trace("failed to process post attributes request msg: {} due to: ", inbound, e); + log.trace("[{}] failed to process post attributes request msg: {} due to: ", ctx.getSessionId(), inbound, e); return jsonAdaptor.convertToPostAttributes(ctx, inbound); } } @@ -60,7 +60,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToGetAttributes(ctx, inbound, topicBase); } catch (AdaptorException e) { - log.trace("failed to process get attributes request msg: {} due to: ", inbound, e); + log.trace("[{}] failed to process get attributes request msg: {} due to: ", ctx.getSessionId(), inbound, e); return jsonAdaptor.convertToGetAttributes(ctx, inbound, topicBase); } } @@ -70,7 +70,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); } catch (AdaptorException e) { - log.trace("failed to process to device rpc response msg: {} due to: ", mqttMsg, e); + log.trace("[{}] failed to process to device rpc response msg: {} due to: ", ctx.getSessionId(), mqttMsg, e); return jsonAdaptor.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase); } } @@ -80,7 +80,7 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToServerRpcRequest(ctx, mqttMsg, topicBase); } catch (AdaptorException e) { - log.trace("failed to process to server rpc request msg: {} due to: ", mqttMsg, e); + log.trace("[{}] failed to process to server rpc request msg: {} due to: ", ctx.getSessionId(), mqttMsg, e); return jsonAdaptor.convertToServerRpcRequest(ctx, mqttMsg, topicBase); } } @@ -90,26 +90,62 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { try { return protoAdaptor.convertToClaimDevice(ctx, inbound); } catch (AdaptorException e) { - log.trace("failed to process claim device request msg: {} due to: ", inbound, e); + log.trace("[{}] failed to process claim device request msg: {} due to: ", ctx.getSessionId(), inbound, e); return jsonAdaptor.convertToClaimDevice(ctx, inbound); } } + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { + log.warn("[{}] invoked not implemented adaptor method! GetAttributeResponseMsg: {} TopicBase: {}", ctx.getSessionId(), responseMsg, topicBase); + return Optional.empty(); + } + @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { return protoAdaptor.convertToGatewayPublish(ctx, deviceName, responseMsg); } + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException { + log.warn("[{}] invoked not implemented adaptor method! AttributeUpdateNotificationMsg: {} Topic: {}", ctx.getSessionId(), notificationMsg, topic); + return Optional.empty(); + } + @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException { return protoAdaptor.convertToGatewayPublish(ctx, deviceName, notificationMsg); } + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException { + log.warn("[{}] invoked not implemented adaptor method! ToDeviceRpcRequestMsg: {} TopicBase: {}", ctx.getSessionId(), rpcRequest, topicBase); + return Optional.empty(); + } + @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException { return protoAdaptor.convertToGatewayPublish(ctx, deviceName, rpcRequest); } + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException { + log.warn("[{}] invoked not implemented adaptor method! ToServerRpcResponseMsg: {} TopicBase: {}", ctx.getSessionId(), rpcResponse, topicBase); + return Optional.empty(); + } + + @Override + public TransportProtos.ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { + log.warn("[{}] invoked not implemented adaptor method! MqttPublishMessage: {}", ctx.getSessionId(), inbound); + return null; + } + + @Override + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException { + log.warn("[{}] invoked not implemented adaptor method! ProvisionDeviceResponseMsg: {}", ctx.getSessionId(), provisionResponse); + return Optional.empty(); + } + @Override public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException { return protoAdaptor.convertToPublish(ctx, firmwareChunk, requestId, chunk, firmwareType); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java index 1543b5c6c7..53ef439eda 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java @@ -60,35 +60,23 @@ public interface MqttTransportAdaptor { ClaimDeviceMsg convertToClaimDevice(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; - default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { - return Optional.empty(); - } + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException; Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, GetAttributeResponseMsg responseMsg) throws AdaptorException; - default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException { - return Optional.empty(); - } + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException; Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; - default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException { - return Optional.empty(); - } + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException; Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; - default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException { - return Optional.empty(); - } + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException; - default ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { - return null; - } + ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; - default Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException { - return Optional.empty(); - } + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException; Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException; diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java index 601018f574..9f0c89714a 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java @@ -134,18 +134,16 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { @Override public void setDeviceProfile(DeviceProfile deviceProfile) { super.setDeviceProfile(deviceProfile); - updateTopicFilters(deviceProfile); - updateAdaptor(); + updateDeviceSessionConfiguration(deviceProfile); } @Override public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { super.onDeviceProfileUpdate(sessionInfo, deviceProfile); - updateTopicFilters(deviceProfile); - updateAdaptor(); + updateDeviceSessionConfiguration(deviceProfile); } - private void updateTopicFilters(DeviceProfile deviceProfile) { + private void updateDeviceSessionConfiguration(DeviceProfile deviceProfile) { DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); if (transportConfiguration.getType().equals(DeviceTransportType.MQTT) && transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) { @@ -158,12 +156,14 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { ProtoTransportPayloadConfiguration protoTransportPayloadConfig = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; updateDynamicMessageDescriptors(protoTransportPayloadConfig); jsonPayloadFormatCompatibilityEnabled = protoTransportPayloadConfig.isEnableCompatibilityWithJsonPayloadFormat(); - useJsonPayloadFormatForDefaultDownlinkTopics = protoTransportPayloadConfig.isUseJsonPayloadFormatForDefaultDownlinkTopics(); + useJsonPayloadFormatForDefaultDownlinkTopics = jsonPayloadFormatCompatibilityEnabled && protoTransportPayloadConfig.isUseJsonPayloadFormatForDefaultDownlinkTopics(); } } else { telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter(); attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter(); + payloadType = TransportPayloadType.JSON; } + updateAdaptor(); } private void updateDynamicMessageDescriptors(ProtoTransportPayloadConfiguration protoTransportPayloadConfig) { @@ -176,17 +176,17 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { public MqttTransportAdaptor getAdaptor(TopicType topicType) { switch (topicType) { case V2: - return getProfileAdaptor(); + return getDefaultAdaptor(); case V2_JSON: return context.getJsonMqttAdaptor(); case V2_PROTO: return context.getProtoMqttAdaptor(); default: - return useJsonPayloadFormatForDefaultDownlinkTopics ? context.getJsonMqttAdaptor() : getProfileAdaptor(); + return useJsonPayloadFormatForDefaultDownlinkTopics ? context.getJsonMqttAdaptor() : getDefaultAdaptor(); } } - private MqttTransportAdaptor getProfileAdaptor() { + private MqttTransportAdaptor getDefaultAdaptor() { return isJsonPayloadType() ? context.getJsonMqttAdaptor() : context.getProtoMqttAdaptor(); } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 85a685aa4b..1a58e1b83b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1099,7 +1099,7 @@ "mqtt-enable-compatibility-with-json-payload-format": "Enable compatibility with other payload formats.", "mqtt-enable-compatibility-with-json-payload-format-hint": "When enabled, the platform will use a Protobuf payload format by default. If parsing fails, the platform will attempt to use JSON payload format. Useful for backward compatibility during firmware updates. For example, the initial release of the firmware uses Json, while the new release uses Protobuf. During the process of firmware update for the fleet of devices, it is required to support both Protobuf and JSON simultaneously. The compatibility mode introduces slight performance degradation, so it is recommended to disable this mode once all devices are updated.", "mqtt-use-json-format-for-default-downlink-topics": "Use Json format for default downlink topics", - "mqtt-use-json-format-for-default-downlink-topics-hint": "When enabled, the platform will use Json payload format to push attributes and RPC via the following topics: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. This setting does not impact attribute and rpc subscriptions sent using new (v2) topics: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. $request_id is an integer request identifier.", + "mqtt-use-json-format-for-default-downlink-topics-hint": "When enabled, the platform will use Json payload format to push attributes and RPC via the following topics: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. This setting does not impact attribute and rpc subscriptions sent using new (v2) topics: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Where $request_id is an integer request identifier.", "snmp-add-mapping": "Add SNMP mapping", "snmp-mapping-not-configured": "No mapping for OID to timeseries/telemetry configured", "snmp-timseries-or-attribute-name": "Timeseries/attribute name for mapping", From c6a50433825049cf77e34bef1bcd1d44eecd94a8 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 27 Oct 2021 13:33:51 +0300 Subject: [PATCH 155/303] UI: New widget settings layout --- .../widget/legend-config.component.html | 46 +++- .../widget/legend-config.component.ts | 176 +++++------- .../widget/widget-config.component.html | 258 ++++++++++-------- .../widget/widget-config.component.scss | 55 +++- .../widget/widget-config.component.ts | 37 ++- .../assets/locale/locale.constant-en_US.json | 11 +- .../assets/locale/locale.constant-ru_RU.json | 11 +- .../assets/locale/locale.constant-uk_UA.json | 11 +- 8 files changed, 355 insertions(+), 250 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html index fd02ac6b34..46faecb9f5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html @@ -15,9 +15,43 @@ limitations under the License. --> - +
    +
    + + legend.direction + + + {{ legendDirectionTranslations.get(legendDirection[direction]) | translate }} + + + + + legend.position + + + {{ legendPositionTranslations.get(legendPosition[pos]) | translate }} + + + +
    +
    + + {{ 'legend.sort-legend' | translate }} + + + {{ 'legend.show-min' | translate }} + + + {{ 'legend.show-max' | translate }} + + + {{ 'legend.show-avg' | translate }} + + + {{ 'legend.show-total' | translate }} + +
    +
    diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts index 6072bf7eaf..d4ec111bb9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts @@ -17,30 +17,21 @@ import { Component, forwardRef, - Inject, - Injector, Input, OnDestroy, OnInit, - StaticProvider, - ViewChild, ViewContainerRef } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { DOCUMENT } from '@angular/common'; -import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ComponentPortal } from '@angular/cdk/portal'; -import { MediaBreakpoints } from '@shared/models/constants'; -import { BreakpointObserver } from '@angular/cdk/layout'; -import { WINDOW } from '@core/services/window.service'; -import { deepClone } from '@core/utils'; -import { LegendConfig } from '@shared/models/widget.models'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { isDefined } from '@core/utils'; import { - LEGEND_CONFIG_PANEL_DATA, - LegendConfigPanelComponent, - LegendConfigPanelData -} from '@home/components/widget/legend-config-panel.component'; - + LegendConfig, + LegendDirection, + legendDirectionTranslationMap, + LegendPosition, + legendPositionTranslationMap +} from '@shared/models/widget.models'; +import { Subscription } from 'rxjs'; // @dynamic @Component({ selector: 'tb-legend-config', @@ -58,105 +49,37 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc @Input() disabled: boolean; - @ViewChild('legendConfigPanelOrigin') legendConfigPanelOrigin: CdkOverlayOrigin; + legendSettings: LegendConfig; + legendConfigForm: FormGroup; + legendDirection = LegendDirection; + legendDirections = Object.keys(LegendDirection); + legendDirectionTranslations = legendDirectionTranslationMap; + legendPosition = LegendPosition; + legendPositions = Object.keys(LegendPosition); + legendPositionTranslations = legendPositionTranslationMap; - innerValue: LegendConfig; + legendSettingsChangesSubscription: Subscription; private propagateChange = (_: any) => {}; - constructor(private overlay: Overlay, - public viewContainerRef: ViewContainerRef, - public breakpointObserver: BreakpointObserver, - @Inject(DOCUMENT) private document: Document, - @Inject(WINDOW) private window: Window) { + constructor(public fb: FormBuilder, + public viewContainerRef: ViewContainerRef) { } ngOnInit(): void { - } - - ngOnDestroy(): void { - } - - openEditMode() { - if (this.disabled) { - return; - } - const isGtSm = this.breakpointObserver.isMatched(MediaBreakpoints['gt-sm']); - const position = this.overlay.position(); - const config = new OverlayConfig({ - panelClass: 'tb-legend-config-panel', - backdropClass: 'cdk-overlay-transparent-backdrop', - hasBackdrop: isGtSm, + this.legendConfigForm = this.fb.group({ + direction: [null, []], + position: [null, []], + sortDataKeys: [null, []], + showMin: [null, []], + showMax: [null, []], + showAvg: [null, []], + showTotal: [null, []] }); - if (isGtSm) { - config.minWidth = '220px'; - config.maxHeight = '300px'; - const panelHeight = 220; - const panelWidth = 220; - const el = this.legendConfigPanelOrigin.elementRef.nativeElement; - const offset = el.getBoundingClientRect(); - const scrollTop = this.window.pageYOffset || this.document.documentElement.scrollTop || this.document.body.scrollTop || 0; - const scrollLeft = this.window.pageXOffset || this.document.documentElement.scrollLeft || this.document.body.scrollLeft || 0; - const bottomY = offset.bottom - scrollTop; - const leftX = offset.left - scrollLeft; - let originX; - let originY; - let overlayX; - let overlayY; - const wHeight = this.document.documentElement.clientHeight; - const wWidth = this.document.documentElement.clientWidth; - if (bottomY + panelHeight > wHeight) { - originY = 'top'; - overlayY = 'bottom'; - } else { - originY = 'bottom'; - overlayY = 'top'; - } - if (leftX + panelWidth > wWidth) { - originX = 'end'; - overlayX = 'end'; - } else { - originX = 'start'; - overlayX = 'start'; - } - const connectedPosition: ConnectedPosition = { - originX, - originY, - overlayX, - overlayY - }; - config.positionStrategy = position.flexibleConnectedTo(this.legendConfigPanelOrigin.elementRef) - .withPositions([connectedPosition]); - } else { - config.minWidth = '100%'; - config.minHeight = '100%'; - config.positionStrategy = position.global().top('0%').left('0%') - .right('0%').bottom('0%'); - } - - const overlayRef = this.overlay.create(config); - - overlayRef.backdropClick().subscribe(() => { - overlayRef.dispose(); - }); - - const injector = this._createLegendConfigPanelInjector( - overlayRef, - { - legendConfig: deepClone(this.innerValue), - legendConfigUpdated: this.legendConfigUpdated.bind(this) - } - ); - - overlayRef.attach(new ComponentPortal(LegendConfigPanelComponent, this.viewContainerRef, injector)); } - private _createLegendConfigPanelInjector(overlayRef: OverlayRef, data: LegendConfigPanelData): Injector { - const providers: StaticProvider[] = [ - {provide: LEGEND_CONFIG_PANEL_DATA, useValue: data}, - {provide: OverlayRef, useValue: overlayRef} - ]; - return Injector.create({parent: this.viewContainerRef.injector, providers}); + ngOnDestroy(): void { + this.removeChangeSubscriptions(); } registerOnChange(fn: any): void { @@ -168,14 +91,45 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; + if (this.disabled) { + this.legendConfigForm.disable({emitEvent: false}); + } else { + this.legendConfigForm.enable({emitEvent: false}); + } + } + + private removeChangeSubscriptions() { + if (this.legendSettingsChangesSubscription) { + this.legendSettingsChangesSubscription.unsubscribe(); + this.legendSettingsChangesSubscription = null; + } + } + + private createChangeSubscriptions() { + this.legendSettingsChangesSubscription = this.legendConfigForm.valueChanges.subscribe( + () => this.legendConfigUpdated() + ); } writeValue(obj: LegendConfig): void { - this.innerValue = obj; + this.legendSettings = obj; + this.removeChangeSubscriptions(); + if (this.legendSettings) { + this.legendConfigForm.patchValue({ + direction: this.legendSettings.direction, + position: this.legendSettings.position, + sortDataKeys: isDefined(this.legendSettings.sortDataKeys) ? this.legendSettings.sortDataKeys : false, + showMin: isDefined(this.legendSettings.showMin) ? this.legendSettings.showMin : false, + showMax: isDefined(this.legendSettings.showMax) ? this.legendSettings.showMax : false, + showAvg: isDefined(this.legendSettings.showAvg) ? this.legendSettings.showAvg : false, + showTotal: isDefined(this.legendSettings.showTotal) ? this.legendSettings.showTotal : false + }); + } + this.createChangeSubscriptions(); } - private legendConfigUpdated(legendConfig: LegendConfig) { - this.innerValue = legendConfig; - this.propagateChange(this.innerValue); + private legendConfigUpdated() { + this.legendSettings = this.legendConfigForm.value; + this.propagateChange(this.legendSettings); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 3be4f1705b..7e69ca704a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -292,12 +292,16 @@
    -
    -
    - widget-config.general-settings -
    -
    - +
    +
    +
    + widget-config.title + + {{ 'widget-config.display-title' | translate }} + +
    + widget-config.title @@ -306,91 +310,139 @@
    -
    - -
    -
    -
    -
    - + + + + widget-config.advanced-settings + + +
    + +
    +
    +
    + widget-config.title-icon + {{ 'widget-config.display-icon' | translate }} - - - -
    -
    - - - - widget-config.icon-size - - -
    -
    -
    -
    - - {{ 'widget-config.display-title' | translate }} - - - {{ 'widget-config.drop-shadow' | translate }} - - - {{ 'widget-config.enable-fullscreen' | translate }} - -
    -
    - -
    -
    -
    -
    - - - - -
    -
    - - widget-config.padding - - - - widget-config.margin - - + +
    + + + + + + widget-config.icon-size + + +
    + + +
    + widget-config.widget-style +
    +
    + + + + +
    +
    + + widget-config.padding + + + + widget-config.margin + + +
    -
    + + {{ 'widget-config.drop-shadow' | translate }} + + + {{ 'widget-config.enable-fullscreen' | translate }} + + + + + widget-config.advanced-settings + + +
    + +
    +
    + +
    + widget-config.legend + + + + + {{ 'widget-config.display-legend' | translate }} + + + + widget-config.advanced-settings + + + + +
    +
    + widget-config.mobile-mode-settings + + + + + {{ 'widget-config.mobile-hide' | translate }} + + + + widget-config.advanced-settings + + +
    + + widget-config.order + + + + widget-config.height + + +
    +
    +
    @@ -402,34 +454,6 @@
    -
    - - {{ 'widget-config.display-legend' | translate }} - -
    - - -
    -
    -
    -
    - widget-config.mobile-mode-settings -
    - - {{ 'widget-config.mobile-hide' | translate }} - - - widget-config.order - - - - widget-config.height - - -
    diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss index 6e1e1cabdf..4c4fa317ce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss @@ -17,9 +17,6 @@ :host { .tb-widget-config { - .tb-advanced-widget-config { - height: 100%; - } .tb-advanced-widget-config { height: 100%; } @@ -69,6 +66,25 @@ padding-left: 8px; } } + .fields-group { + padding: 0 16px 8px; + margin-bottom: 10px; + border: 1px groove rgba(0, 0, 0, .25); + border-radius: 4px; + legend { + color: rgba(0, 0, 0, .7); + width: fit-content; + } + } + .fields-group-slider { + padding: 0; + legend { + margin-left: 16px; + } + .tb-settings { + padding: 0 16px 8px; + } + } } } @@ -94,6 +110,36 @@ white-space: normal; } .mat-expansion-panel { + &.tb-settings { + box-shadow: none; + .mat-content { + overflow: visible; + } + .mat-expansion-panel-header { + padding: 0; + &:hover { + background: none; + } + .mat-expansion-indicator { + padding: 2px; + } + } + .mat-expansion-panel-header-description { + align-items: center; + } + .mat-expansion-panel-body{ + padding: 0 0 16px; + } + .tb-json-object-panel { + margin: 0; + } + .mat-checkbox-layout { + margin: 5px 0; + } + .mat-checkbox-inner-container { + margin-right: 12px; + } + } &.tb-datasources { &.mat-expanded { overflow: visible; @@ -152,5 +198,8 @@ } } } + .mat-slide-toggle-content { + white-space: normal; + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 7351f9985a..48ed4bf700 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -212,11 +212,28 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont showLegend: [null, []], legendConfig: [null, []] }); + this.widgetSettings.get('showTitle').valueChanges.subscribe((value: boolean) => { + if (value) { + this.widgetSettings.get('titleStyle').enable({emitEvent: false}); + this.widgetSettings.get('titleTooltip').enable({emitEvent: false}); + this.widgetSettings.get('showTitleIcon').enable({emitEvent: false}); + } else { + this.widgetSettings.get('titleStyle').disable({emitEvent: false}); + this.widgetSettings.get('titleTooltip').disable({emitEvent: false}); + this.widgetSettings.get('showTitleIcon').patchValue(false); + this.widgetSettings.get('showTitleIcon').disable({emitEvent: false}); + } + }); + this.widgetSettings.get('showTitleIcon').valueChanges.subscribe((value: boolean) => { if (value) { this.widgetSettings.get('titleIcon').enable({emitEvent: false}); + this.widgetSettings.get('iconColor').enable({emitEvent: false}); + this.widgetSettings.get('iconSize').enable({emitEvent: false}); } else { this.widgetSettings.get('titleIcon').disable({emitEvent: false}); + this.widgetSettings.get('iconColor').disable({emitEvent: false}); + this.widgetSettings.get('iconSize').disable({emitEvent: false}); } }); this.widgetSettings.get('showLegend').valueChanges.subscribe((value: boolean) => { @@ -236,6 +253,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont }); } + ngOnDestroy(): void { + this.removeChangeSubscriptions(); + } + private removeChangeSubscriptions() { if (this.dataSettingsChangesSubscription) { this.dataSettingsChangesSubscription.unsubscribe(); @@ -376,7 +397,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont iconColor: isDefined(config.iconColor) ? config.iconColor : 'rgba(0, 0, 0, 0.87)', iconSize: isDefined(config.iconSize) ? config.iconSize : '24px', titleTooltip: isDefined(config.titleTooltip) ? config.titleTooltip : '', - showTitle: config.showTitle, + showTitle: isDefined(config.showTitle) ? config.showTitle : false, dropShadow: isDefined(config.dropShadow) ? config.dropShadow : true, enableFullscreen: isDefined(config.enableFullscreen) ? config.enableFullscreen : true, backgroundColor: config.backgroundColor, @@ -396,11 +417,25 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont }, {emitEvent: false} ); + const showTitle: boolean = this.widgetSettings.get('showTitle').value; + if (showTitle) { + this.widgetSettings.get('titleTooltip').enable({emitEvent: false}); + this.widgetSettings.get('titleStyle').enable({emitEvent: false}); + this.widgetSettings.get('showTitleIcon').enable({emitEvent: false}); + } else { + this.widgetSettings.get('titleTooltip').disable({emitEvent: false}); + this.widgetSettings.get('titleStyle').disable({emitEvent: false}); + this.widgetSettings.get('showTitleIcon').disable({emitEvent: false}); + } const showTitleIcon: boolean = this.widgetSettings.get('showTitleIcon').value; if (showTitleIcon) { this.widgetSettings.get('titleIcon').enable({emitEvent: false}); + this.widgetSettings.get('iconColor').enable({emitEvent: false}); + this.widgetSettings.get('iconSize').enable({emitEvent: false}); } else { this.widgetSettings.get('titleIcon').disable({emitEvent: false}); + this.widgetSettings.get('iconColor').disable({emitEvent: false}); + this.widgetSettings.get('iconSize').disable({emitEvent: false}); } const showLegend: boolean = this.widgetSettings.get('showLegend').value; if (showLegend) { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 16788b9adc..dd719d3258 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3026,16 +3026,16 @@ "title": "Title", "title-tooltip": "Title Tooltip", "general-settings": "General settings", - "display-title": "Display title", + "display-title": "Display widget title", "drop-shadow": "Drop shadow", - "enable-fullscreen": "Enable fullscreen", + "enable-fullscreen": "Allow fullscreen", "background-color": "Background color", "text-color": "Text color", "padding": "Padding", "margin": "Margin", "widget-style": "Widget style", "title-style": "Title style", - "mobile-mode-settings": "Mobile mode settings", + "mobile-mode-settings": "Mobile mode", "order": "Order", "height": "Height", "mobile-hide": "Hide widget in mobile mode", @@ -3044,6 +3044,7 @@ "timewindow": "Timewindow", "use-dashboard-timewindow": "Use dashboard timewindow", "display-timewindow": "Display timewindow", + "legend": "Legend", "display-legend": "Display legend", "datasources": "Datasources", "maximum-datasources": "Maximum { count, plural, 1 {1 datasource is allowed.} other {# datasources are allowed} }", @@ -3071,9 +3072,11 @@ "delete-action": "Delete action", "delete-action-title": "Delete widget action", "delete-action-text": "Are you sure you want delete widget action with name '{{actionName}}'?", + "title-icon": "Title icon", "display-icon": "Display title icon", "icon-color": "Icon color", - "icon-size": "Icon size" + "icon-size": "Icon size", + "advanced-settings": "Advanced settings" }, "widget-type": { "import": "Import widget type", diff --git a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json index 35df70e300..65381458ce 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json @@ -1631,7 +1631,7 @@ "advanced": "Дополнительно", "title": "Название", "general-settings": "Общие настройки", - "display-title": "Показать название", + "display-title": "Показать название на виджете", "drop-shadow": "Тень", "enable-fullscreen": "Во весь экран", "background-color": "Цвет фона", @@ -1640,7 +1640,7 @@ "margin": "Margin", "widget-style": "Стиль виджета", "title-style": "Стиль названия", - "mobile-mode-settings": "Настройки мобильного режима", + "mobile-mode-settings": "Мобильный режим", "order": "Порядок", "height": "Высота", "units": "Специальный символ после значения", @@ -1648,6 +1648,7 @@ "timewindow": "Временное окно", "use-dashboard-timewindow": "Использовать временное окно дашборда", "display-timewindow": "Показывать временное окно", + "legend": "Легенда", "display-legend": "Показать легенду", "datasources": "Источники данных", "maximum-datasources": "Максимальной количество источников данных равно {{count}}", @@ -1673,9 +1674,11 @@ "delete-action": "Удалить действие", "delete-action-title": "Удалить действие виджета", "delete-action-text": "Вы точно хотите удалить действие виджета '{{actionName}}'?", - "display-icon": "Показывать иконку в названии", + "title-icon": "Иконка в названии виджета", + "display-icon": "Показывать иконку в названии виджета", "icon-color": "Цвет иконки", - "icon-size": "Размер иконки" + "icon-size": "Размер иконки", + "advanced-settings": "Расширенные настройки" }, "widget-type": { "import": "Импортировать тип виджета", diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index 257a3519a9..b4620a937d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -2202,7 +2202,7 @@ "advanced": "Додатково", "title": "Назва", "general-settings": "Загальні налаштування", - "display-title": "Відобразити назву", + "display-title": "Відобразити назву у віджеті", "drop-shadow": "Тінь", "enable-fullscreen": "Увімкнути повноекранний режим", "enable-data-export": "Увімкнути експорт даних", @@ -2212,7 +2212,7 @@ "margin": "Границі", "widget-style": "Стиль віджетів", "title-style": "Стиль заголовка", - "mobile-mode-settings": "Налаштування мобільного режиму", + "mobile-mode-settings": "мобільний режим", "order": "Порядок", "height": "Висота", "units": "Спеціальний символ після значення", @@ -2220,6 +2220,7 @@ "timewindow": "Вікно часу", "use-dashboard-timewindow": "Використати вікно часу на панелі візуалізації", "display-timewindow": "Показувати вікно часу", + "legend": "Легенда", "display-legend": "Показати легенду", "datasources": "Джерела даних", "maximum-datasources": "Максимально { count, plural, 1 {1 дозволене джерело даних.} other {# дозволені джерела даних } }", @@ -2245,9 +2246,11 @@ "delete-action": "Видалити дію", "delete-action-title": "Видалити дію віджета", "delete-action-text": "Ви впевнені, що хочете видалити дію віджета '{{actionName}}'?", - "display-icon": "Показувати іконку у назві", + "title-icon": "Іконка у назві віджету", + "display-icon": "Показувати іконку у назві віджету", "icon-color": "Колір іконки", - "icon-size": "Розмір іконки" + "icon-size": "Розмір іконки", + "advanced-settings": "Розширені налаштування" }, "widget-type": { "import": "Імпортувати тип віджета", From 483a69fed1981ee07e14b9b00f15f6f515828b82 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 27 Oct 2021 14:19:50 +0300 Subject: [PATCH 156/303] Use SSL credentials configuration to setup HTTPS. Enable Lwm2m credentials by default. --- .../server/ThingsboardInstallApplication.java | 1 + .../src/main/resources/thingsboard.yml | 50 +++++++---- .../server/common/data/ResourceUtils.java | 81 +++++++++++------- .../lwm2m/src/main/resources/lwm2mserver.jks | Bin 3953 -> 3849 bytes .../config/ssl/AbstractSslCredentials.java | 12 ++- .../config/ssl/KeystoreSslCredentials.java | 5 ++ .../config/ssl/PemSslCredentials.java | 15 +++- .../transport/config/ssl/SslCredentials.java | 7 ++ .../SslCredentialsWebServerCustomizer.java | 71 +++++++++++++++ .../src/main/resources/tb-coap-transport.yml | 4 +- .../src/main/resources/tb-http-transport.yml | 30 ++++++- .../src/main/resources/tb-lwm2m-transport.yml | 14 +-- 12 files changed, 225 insertions(+), 65 deletions(-) create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsWebServerCustomizer.java diff --git a/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java b/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java index 32c995ac82..996ca23e9c 100644 --- a/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java +++ b/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java @@ -31,6 +31,7 @@ import java.util.Arrays; "org.thingsboard.server.service.install", "org.thingsboard.server.dao", "org.thingsboard.server.common.stats", + "org.thingsboard.server.common.transport.config.ssl", "org.thingsboard.server.cache"}) public class ThingsboardInstallApplication { diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index f88d5f297c..b9f9feec7b 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -23,14 +23,30 @@ server: ssl: # Enable/disable SSL support enabled: "${SSL_ENABLED:false}" - # Path to the key store that holds the SSL certificate - key-store: "${SSL_KEY_STORE:classpath:keystore/keystore.p12}" - # Password used to access the key store - key-store-password: "${SSL_KEY_STORE_PASSWORD:thingsboard}" - # Type of the key store - key-store-type: "${SSL_KEY_STORE_TYPE:PKCS12}" - # Alias that identifies the key in the key store - key-alias: "${SSL_KEY_ALIAS:tomcat}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${SSL_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${SSL_PEM_CERT:server.pem}" + # Path to the server certificate private key file (optional) + key_file: "${SSL_PEM_KEY:server_key.pem}" + # Server certificate private key password (optional) + key_password: "${SSL_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${SSL_KEY_STORE_TYPE:PKCS12}" + # Path to the key store that holds the SSL certificate + store_file: "${SSL_KEY_STORE:classpath:keystore/keystore.p12}" + # Password used to access the key store + store_password: "${SSL_KEY_STORE_PASSWORD:thingsboard}" + # Key alias + key_alias: "${SSL_KEY_ALIAS:tomcat}" + # Password used to access the key + key_password: "${SSL_KEY_PASSWORD:thingsboard}" log_controller_error_stack_trace: "${HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE:false}" ws: send_timeout: "${TB_SERVER_WS_SEND_TIMEOUT:5000}" @@ -679,10 +695,10 @@ transport: store_file: "${COAP_DTLS_KEY_STORE:coapserver.jks}" # Password used to access the key store store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" # Key alias key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}" + # Password used to access the key + key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" x509: # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" @@ -702,7 +718,7 @@ transport: # Server X509 Certificates support credentials: # Whether to enable LWM2M server X509 Certificate/RPK support - enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}" + enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:true}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}" # PEM server credentials @@ -721,10 +737,10 @@ transport: store_file: "${LWM2M_SERVER_KEY_STORE:lwm2mserver.jks}" # Password used to access the key store store_password: "${LWM2M_SERVER_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_key_password}" # Key alias key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" + # Password used to access the key + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}" # Only Certificate_x509: skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" bootstrap: @@ -738,7 +754,7 @@ transport: # Bootstrap server X509 Certificates support credentials: # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support - enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}" + enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:true}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}" # PEM server credentials @@ -757,15 +773,15 @@ transport: store_file: "${LWM2M_BS_KEY_STORE:lwm2mserver.jks}" # Password used to access the key store store_password: "${LWM2M_BS_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${LWM2M_BS_KEY_PASSWORD:server_key_password}" # Key alias key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}" + # Password used to access the key + key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}" security: # X509 trust certificates trust-credentials: # Whether to load X509 trust certificates - enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}" + enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:true}" # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore) type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}" # PEM certificates diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java index b354b98bdb..e4b7cf3c1b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java @@ -27,27 +27,36 @@ import java.net.URL; @Slf4j public class ResourceUtils { + public static final String CLASSPATH_URL_PREFIX = "classpath:"; + public static boolean resourceExists(Object classLoaderSource, String filePath) { return resourceExists(classLoaderSource.getClass().getClassLoader(), filePath); } public static boolean resourceExists(ClassLoader classLoader, String filePath) { - File resourceFile = new File(filePath); - if (resourceFile.exists()) { - return true; - } else { - InputStream classPathStream = classLoader.getResourceAsStream(filePath); - if (classPathStream != null) { + boolean classPathResource = false; + String path = filePath; + if (path.startsWith(CLASSPATH_URL_PREFIX)) { + path = path.substring(CLASSPATH_URL_PREFIX.length()); + classPathResource = true; + } + if (!classPathResource) { + File resourceFile = new File(path); + if (resourceFile.exists()) { return true; - } else { - try { - URL url = Resources.getResource(filePath); - if (url != null) { - return true; - } - } catch (IllegalArgumentException e) {} } } + InputStream classPathStream = classLoader.getResourceAsStream(path); + if (classPathStream != null) { + return true; + } else { + try { + URL url = Resources.getResource(path); + if (url != null) { + return true; + } + } catch (IllegalArgumentException e) {} + } return false; } @@ -56,32 +65,40 @@ public class ResourceUtils { } public static InputStream getInputStream(ClassLoader classLoader, String filePath) { + boolean classPathResource = false; + String path = filePath; + if (path.startsWith(CLASSPATH_URL_PREFIX)) { + path = path.substring(CLASSPATH_URL_PREFIX.length()); + classPathResource = true; + } try { - InputStream keyStoreInputStream; - File keyStoreFile = new File(filePath); - if (keyStoreFile.exists()) { - log.info("Reading key store from file {}", filePath); - keyStoreInputStream = new FileInputStream(keyStoreFile); + if (!classPathResource) { + File resourceFile = new File(path); + if (resourceFile.exists()) { + log.info("Reading resource data from file {}", filePath); + return new FileInputStream(resourceFile); + } + } + InputStream classPathStream = classLoader.getResourceAsStream(path); + if (classPathStream != null) { + log.info("Reading resource data from class path {}", filePath); + return classPathStream; } else { - InputStream classPathStream = classLoader.getResourceAsStream(filePath); - if (classPathStream != null) { - log.info("Reading key store from class path {}", filePath); - keyStoreInputStream = classPathStream; - } else { - URI uri = Resources.getResource(filePath).toURI(); - log.info("Reading key store from URI {}", filePath); - keyStoreInputStream = new FileInputStream(new File(uri)); + URL url = Resources.getResource(path); + if (url != null) { + URI uri = url.toURI(); + log.info("Reading resource data from URI {}", filePath); + return new FileInputStream(new File(uri)); } } - return keyStoreInputStream; } catch (Exception e) { if (e instanceof NullPointerException) { log.warn("Unable to find resource: " + filePath); } else { log.warn("Unable to find resource: " + filePath, e); } - throw new RuntimeException("Unable to find resource: " + filePath); } + throw new RuntimeException("Unable to find resource: " + filePath); } public static String getUri(Object classLoaderSource, String filePath) { @@ -90,10 +107,10 @@ public class ResourceUtils { public static String getUri(ClassLoader classLoader, String filePath) { try { - File keyStoreFile = new File(filePath); - if (keyStoreFile.exists()) { - log.info("Reading key store from file {}", filePath); - return keyStoreFile.getAbsolutePath(); + File resourceFile = new File(filePath); + if (resourceFile.exists()) { + log.info("Reading resource data from file {}", filePath); + return resourceFile.getAbsolutePath(); } else { URL url = classLoader.getResource(filePath); return url.toURI().toString(); diff --git a/common/transport/lwm2m/src/main/resources/lwm2mserver.jks b/common/transport/lwm2m/src/main/resources/lwm2mserver.jks index 9f6748f8fdab7179b895eccd71421fe1565d27db..5fab824aa1b19928fe711701cd27857472a9e739 100644 GIT binary patch delta 3653 zcmV-L4!ZI29*G_zFoF*S0s#Xsf)2h02`Yw2hW8Bt2LYgh4zC1)4y!PN4yTbKM1Ly* zom9BjJH$VcW(h0D2xIlY6r2JB0K-rOftaAyg&4(nOgQGgqZXKQNpgf$5vgZ}((Ysq z4>NDXm)2g@Mz`$C_E~pf2sbe$VNxNWg7CwD5uTlTd647vCxxS`5^~+i%3oo$<=Ut7 z96^zpSju@r$84gNVErKYNtV0q%r!bu0bINIX>{=o{Yo;qIe}jww@|a@ui(dgepJ8kd7lOaQD49BSZNR~ob$&O zk7x0cF9b%YM6(;R& z>c*G%1)}{X$%f_0t8V_&LNQU|0xkI3^#2v9Vh5%nhr zdsYmeWIv&B_#`cG{+tpJXY%zh<=zWf`~HA8b=FeEgQU!~(4G ztKp3!X7^z8TDs_-``@hRMC~tFi0__dxX*0}y=Ku+K_v3MQFss)6Mo3)N80o-GGc*W zqtL?nMDyA^8LxWo6s#(8BiGE*b(LJ80%S2I&;7tsS(Iud<2!Pq_7 z>J=D1|4`9nwAA=Bq*ee8T-oXYHqazGaBBxrAXf*xG306XETw{w1^@SbxoZrvB@7;< zIy#$$kn-oXcBOFb)gkUIjST)S6{Ak92W>iRfVl+>usEb%U`2m36mhpc(00T)sv9GL zZ$jfE=kcjZc;`J2HCB6CQ+Eo7vSpHPUfWuethbwDt_0oBbK8itz))(CMpr(R5B)?P zr~DX{n}1`D_WP?4W03usm03LnEe=atcZtA`B*4ji@MFI(hQ39`@cD~Jm?|Q>hp}MW zBP@1lTH|X@8(n|F3|tdOGU;dyMo*r%EEoj4(AO?W6L_WzK@B8a=dAk*lyd}Y<7RD8 zDR_+ERe&|!dTY>%hp9MP7c&=^FE3G%ga}k|^ApCxZyug=Q~wXW5j~F7WcH?x(18$d$?BpD-!$GC$eMt*93*}cRz@aC95vE zbo>Sjw~sSB?w+EcFhyjs5{!UFV^-YTX%vVAhx>n^P-^UJXp-RJAa8XB*qyRCj4cb- zRtI9BFx%wgz?Us z>oeetM}}cMV%1rd6J2x=wbRcLN|8R~st2r>ihqh38kECo?4fkJ)xNFJY}~=Z($G^E zA4-3tRMmld%nq7rkiC7%j-v#>2eMo|rUrNcT5$ea>7}Xj%0nMK0{lqoAh{EZWMFU2 z?!>~Mgb!SzeS4;xt}k}YQPqtxR@Yn-@Hk5Wx~hyDCk?gu)|OLkjL1s{>wRy@#2VmJ znoX1$=4b9mXv3K@I|f|Vd$T-lnF@i5Gpv7p{faHOI1{2$$;VcAM3>05@M7iAS`rs$ z*>pBhPp@>$(p>6^lmSApfZ%ati8_sF%z5n?;Gd^})wsAe;;qNqGJ5EEVj_h^rjoiWJAij^KT^KiemaQ*LCt~Vc3%5HuZn3TM|`;hAj3=a2h^{>eVrKIz$R}Fvl zJmCbxlRb|8U1EGj>#%#?-0qpbg5%1jjtN{&7vZS1JWUwzOU*9CNd2I*Bh-IfF^e%EmB7aaH-T0k*XL=`2^+C)>&jSZDe07V z|I4%HQH%Z1cDBB=vQ{6O*i<~L$P2-tsvZF+z6@(L<9ULG}>YN;%*B} zo&7)}<#)+(z{3{ma15xSj5$<%gE8F$A`EY_1d*@2ih?hm5)@&g{7Mb)ksyDSG8&tf zy48HrJ=34^yU*BnZ-6)`d`kR{RlA-@FbKSdbT#z*a`oMRyDQ}(Y!Qz!7PXIi?fNU+8JZJq?OJ9`gFo!Nn# zJCbbf)Pv82Lg$-wQ^T0FuBCqjsZnQZ_=7L}nJGtg^kAfH_h>wCtmB=X(v5|JM&@4J z*!#O;?Iq-XrN~m6R?p#9m)=}89sSH4jHKB;+L4A}Oi}=aCpZbb)W4d$ycoK`a@(&nXPD_7-8se;v2?#i@ z5|D*$W`hvY#F2L^dgS||;U-%m<8vK$+$eenj(YkZGz`+!`utjH=I*+sSFly$5KZK- zFSX4GPUe4~V!<7M_@B_sv@R4UoRo~)Ch$#3{30wRJ}2$##*6+N0F0Nv8NK-)mpX% z@4ostl_4ISiSl`rqt%-|_XE@aqA8<&YKiWy4$Z;oCpZ5nke+|c+~anTHd3P{mchxm ziE75=L4LzN-xtubZ8rc8A5+5}2#^ait_(WiB%^Z9ZWf=I=!O~HFS36eL^p6)v7Y5I zHz=sWEy^;s*M!^Fc)G|#SVGq}IHPJQOMBumSC^kVQ=~>gBr+a+Rq^?u{AGuFAQC@k zga)8!>>xqoC)nH6A<3~Y3s`@$#AV!Yr@k@`^o)oX>E1sT~Ag1wYDw5<6 zKV?q$Z-+AvG4p83!1rXSjAb!yr3$w4j0RBTz~66KXsds>x#XDMYi3=pj>usTFx|%e z2eODYW|KtQ`#XAByPJWfo?Pl>Y`FFf85H$>vVpi1+tlTD%@T}rSh`0Qj&hHNA4Y?| zOPd^d=-Zj_qh z)daLS3Q_pFP7FV!9CMWn*||txn|zMf8}{Jbz&sV9Q4sV%qUMzf@94TQ9jiR|;Qyr6 zb5g1e=SHGl^<8Y;LJ>?l!$^!hP=4 zWm$j!_x{)#<)ro~78OK;d#S{RBNWNJ;i?W`h9Q=9m(#`#uhmanl9}D7KVW!QHs`I- zt_jMk?j3^zaB9wh8rlvdeMQfNAe?3OXp#e_MLJ>nJ;)IVeyYZ8MSt`=*@GH-9sr@< zs-P+(o5bz0Fg`FLFbM_)D-Ht!8U+9Z6xYT>#LaQo(*VtnzN_qMP4M!Fhy)b<1nu-# X_d}DEK0Izji}dfgHE9+C0|ADhaZ(kz delta 3758 zcmV;f4pH%m9`PO`FoF+l0s#Xsf)6GJ2`Yw2hW8Bt2LYgh4;KW24-+tg4-b(dM1S-i z{srVqTGKEDaK2q&C*civrQ!ku0K-rOftY_W?dJLp*IR#Gc*!!xkpxE?wSF%W|6}_C zVqQ(g1?5uTlGag0&^c3`lU=^W>izj-T7{iDN&27>DOY+qHvUmtH2n3den$f;82fv2 zmBu!DS_FEdwT7F%f~R0@YJ42Rk2T5+bK`W-6?=o4(zV>6+8)fW5y+KjISE|QdhbFS ze3x#V^%TSREb9F`ENS$a>+MLW9--%x8UZ&CF*7nUHaIjmG&nLaf&n3sK_!1B5v#8o zUP=N1_%{{P>a~$lh=*DN0|3KN1c8{f3i>!()nXP2mOE4kkxSw!Hox+qA(3G2T$Sb* z*?Hl6f+<7&D3!y&QLoC~J2mf1y$-(Ls@OYsgBij&LNQU)RNo3>bAG$3Rz_n)NE)9t=eP2Ke*b)I2qPlt>Tk8!{cz5t1oikCNS1 zCcHPY|G_#|MCQm~`l1{{Zx@20KQjKfbxrTjr&KpZc4U$#j1pA5yKoOjLyA zAGBtRSisO-F9=!rwy#ko&xnl-^7-qYb87KZ08QTTwwa1vZ=ran1-van5_znwqoC6M zr_C=XqZT_9YnId8=>2QPgIhw0Z_PpLqxzzwDJKeZ&V1+De>Yx@AC_nJo}lUFEuBgd z3kRt=5Aj2$cm<%_CIq0Z> z@~)y&cPOg!<~6^O5N;Xm8w2PQxLX=oC1T9Fh`EyU<1O`?ar}Ql1j@^4g1bno6P@tj zC07JVoS2;6Z2b+$a2G7Eevy=zj$U zJlkqdCriZmaQG9|!W(0b%weA%o$s+tLF#L|y&8udAAb!zZw<#J!r_#_pEN-J0dy!r z++6QEOW$*1fsB7N3YQpmS#Syy7N}6qV!5O40tCr!t^JA)rDSOgOai|;p6zJwj_q( z06;bY`T19Pyl*YNYd33n3o34U!PwIQV0-^!M>FqQK<6@X^Iam(6aXxv2QP+L%qMZF zzpH)egz$gNNw%pMeekD5#0E_YOg!>6^`PucYmlo^$snKT zFJC%2E4(7)0f7i+VLc>_rQ6Ft(WUq}KxyLb+H8LttD*Se=H^xfV6VpEYq-u7aF83W zarF6tIoO5FKce|qn6w8a*wrN;)R11|pQ~l@@DsWwJ=Y7PVF$(mO-9cei-Gb{geXMt zKa*N3RZh=+!>UZKaLN(;#tHEf4#dC&@2&`W(Srf*bzv*_n^)hj&_b01>&;J`31l z(1}w7mP1uT7WxvERM16tE#*6U+yFF7Upa5L*B+B-NDZl_P~M}tDe&okQhg$V;ktiD zV^NUY^@4!~l31+g=jB#3*!F2SgwB5|)$T&b{h4w)Yavalvk~mbMmiIaRvx%vS!uuk zL1UvtC}lR+*`TkDHmt-Dfi$6@A$E&oV}!>S2b^jqfzmh`t=2gS`Ke%xZ}|1F_Jp%w zrIKuDOSf(tpg8Qa7p|jm?YX||zTxo~NTRCBSyD4t!t`)fWiD70COw=UPp*Hev!tQn z^44DgA}8B?Oqf$ECe>t;R=}%78o!yc$Jh_pc1fd~zx_W!mmG0?QunF9#es|?Zm^?Z zlLCct^SEnEMz_Xuyk0d2c~c3vEy9!~s>fZ-L5Kw2n9JS3_|>QiHg_pbj@sDp$7p`g z2w0I=0~MDJ9|KJhU;|-5w+Dax9-52ik*iW);Nr|+y@AylI_9;$tzeFS_}=|rg%9h} zogN`kY)D%rURD$Uf8oZg->{#4{k;MJM~X;)f`$gUw`V0t)>5nb--SpGUjMbq4Wbzm zy{oJx6~I{-OW@_ne8&IlLm**XS-V|rFnBBGSEeI2T;nCdV=@7ymfnATIB4XLeZD`` z(Tu~>sovCMYKTS>6gqe1!M?i-G6s-$2MuZLbh9NlzvSRW7jf6C;x2wy%}N*eC@AHB zPUU=Gj9#JOXR4dmpGsE?48meK^)Lgn^-yrAiEDaD*LuS+2~^#oQ)rLOIJ^&56W)FZ=A}u4m8##UC&C-G*nMTgm(38T&SR z?1(FWOY!Ypa2%}h=t5t)INw@L;qJ!68jqPhx)L z-E1PfXH?2kRYVinz&+Rp#VL z^1Lmcc2$0}=)9z)c3^`+tN1GaG{r#ZL&iNXZ{3Q%cJt0lKf1b|aCAd|tlqyTN+FV~8O%+Y4J0IDXKP)S znZRdG8euiXnVsX*2a~-g9QZYD=CkiH5?J>2ldTr0U_z5I=?EsbWlGkM$Ab-!Hjf#R zDJ-FbsuvSjx@0s#MgBmzZ_J*~JVz6`$OvLmQayj>)fIbeN+CgEMQ${Z5f)cOK@l{AyD=YZZsu>XwMF}_E|Lr$}-Vlv$aBN8+U zIXHjxcXZ+c#=okogeWoalI4N6r^i+CP&}`d2|5mmgB2AjiANzX1dEsS!CYj!p>C0< z20euq-Mob|^0$+Mgtk09EG)Y>qW+FtJ0(>!uNe>#E(e|PNO8qAxigumEjsQUy#4c^ z7_6iUE{bIsE3H}m>WUXAD^-LAOJ2pyGj4w_lfaz|QqF%Dx+T$)CTmyo(#6N3(RY1{ z0Wt(;QX*T8c>P!Npaas2QHN48Y$?A0G;kW$7?cW;jH3^rX6y~4nf}|L^lQFk_%(F9 zLhK}#H+IPKl5cmQGRu|HSt5(!+*Q)?4P^chb+LpjDpQb|%dkUO!p|<~&-!`bvUq=_ zVXoO)iogr>B&(<$=h1?Abc@rfUD}-3T#DH2jOu zXAl25fHe(E3pcvz=t$e|htX7_%QAn^Qtl&Ln>|s^4)5A@t*?G9w!0Jf5!&V=Q-}UN z path = certPath.getCertificates(); Certificate[] x509Certificates = path.toArray(new Certificate[0]); - keyStore.setKeyEntry(this.keyAlias, privateKey, keyPasswordArray, x509Certificates); + keyStore.setKeyEntry(DEFAULT_KEY_ALIAS, privateKey, keyPasswordArray, x509Certificates); } return keyStore; } + + @Override + public String getKeyAlias() { + return DEFAULT_KEY_ALIAS; + } + + @Override + protected void updateKeyAlias(String keyAlias) { + } } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java index ef412815d7..c6207b877d 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java @@ -19,6 +19,7 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.security.GeneralSecurityException; +import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; @@ -30,6 +31,12 @@ public interface SslCredentials { void init(boolean trustsOnly) throws IOException, GeneralSecurityException; + KeyStore getKeyStore(); + + String getKeyPassword(); + + String getKeyAlias(); + PrivateKey getPrivateKey(); PublicKey getPublicKey(); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsWebServerCustomizer.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsWebServerCustomizer.java new file mode 100644 index 0000000000..054d4f6195 --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsWebServerCustomizer.java @@ -0,0 +1,71 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.config.ssl; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.SslStoreProvider; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.security.KeyStore; + +@Component +@ConditionalOnExpression("'${spring.main.web-environment:true}'=='true' && '${server.ssl.enabled:false}'=='true'") +public class SslCredentialsWebServerCustomizer implements WebServerFactoryCustomizer { + + @Bean + @ConfigurationProperties(prefix = "server.ssl.credentials") + public SslCredentialsConfig httpServerSslCredentials() { + return new SslCredentialsConfig("HTTP Server SSL Credentials", false); + } + + @Autowired + @Qualifier("httpServerSslCredentials") + private SslCredentialsConfig httpServerSslCredentialsConfig; + + private final ServerProperties serverProperties; + + public SslCredentialsWebServerCustomizer(ServerProperties serverProperties) { + this.serverProperties = serverProperties; + } + + @Override + public void customize(ConfigurableServletWebServerFactory factory) { + SslCredentials sslCredentials = this.httpServerSslCredentialsConfig.getCredentials(); + Ssl ssl = serverProperties.getSsl(); + ssl.setKeyAlias(sslCredentials.getKeyAlias()); + ssl.setKeyPassword(sslCredentials.getKeyPassword()); + factory.setSsl(ssl); + factory.setSslStoreProvider(new SslStoreProvider() { + @Override + public KeyStore getKeyStore() { + return sslCredentials.getKeyStore(); + } + + @Override + public KeyStore getTrustStore() { + return null; + } + }); + } +} diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index adaffed7de..0caf66a36e 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -118,10 +118,10 @@ transport: store_file: "${COAP_DTLS_KEY_STORE:coapserver.jks}" # Password used to access the key store store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" # Key alias key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}" + # Password used to access the key + key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" x509: # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index f35f4136e7..603698c2df 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -19,6 +19,34 @@ server: address: "${HTTP_BIND_ADDRESS:0.0.0.0}" # Server bind port port: "${HTTP_BIND_PORT:8081}" + # Server SSL configuration + ssl: + # Enable/disable SSL support + enabled: "${SSL_ENABLED:false}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${SSL_CREDENTIALS_TYPE:PEM}" + # PEM server credentials + pem: + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) + cert_file: "${SSL_PEM_CERT:server.pem}" + # Path to the server certificate private key file (optional) + key_file: "${SSL_PEM_KEY:server_key.pem}" + # Server certificate private key password (optional) + key_password: "${SSL_PEM_KEY_PASSWORD:server_key_password}" + # Keystore server credentials + keystore: + # Type of the key store + type: "${SSL_KEY_STORE_TYPE:PKCS12}" + # Path to the key store that holds the SSL certificate + store_file: "${SSL_KEY_STORE:classpath:keystore/keystore.p12}" + # Password used to access the key store + store_password: "${SSL_KEY_STORE_PASSWORD:thingsboard}" + # Key alias + key_alias: "${SSL_KEY_ALIAS:tomcat}" + # Password used to access the key + key_password: "${SSL_KEY_PASSWORD:thingsboard}" # Zookeeper connection parameters. Used for service discovery. zk: @@ -283,4 +311,4 @@ management: web: exposure: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). - include: '${METRICS_ENDPOINTS_EXPOSE:info}' \ No newline at end of file + include: '${METRICS_ENDPOINTS_EXPOSE:info}' diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index be5bb62a00..be51848337 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -114,7 +114,7 @@ transport: # Server X509 Certificates support credentials: # Whether to enable LWM2M server X509 Certificate/RPK support - enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}" + enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:true}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}" # PEM server credentials @@ -133,10 +133,10 @@ transport: store_file: "${LWM2M_SERVER_KEY_STORE:lwm2mserver.jks}" # Password used to access the key store store_password: "${LWM2M_SERVER_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_key_password}" # Key alias key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" + # Password used to access the key + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}" # Only Certificate_x509: skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" bootstrap: @@ -150,7 +150,7 @@ transport: # Bootstrap server X509 Certificates support credentials: # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support - enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}" + enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:true}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}" # PEM server credentials @@ -169,15 +169,15 @@ transport: store_file: "${LWM2M_BS_KEY_STORE:lwm2mserver.jks}" # Password used to access the key store store_password: "${LWM2M_BS_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key - key_password: "${LWM2M_BS_KEY_PASSWORD:server_key_password}" # Key alias key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}" + # Password used to access the key + key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}" security: # X509 trust certificates trust-credentials: # Whether to load X509 trust certificates - enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}" + enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:true}" # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore) type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}" # PEM certificates From 84f2bdd2dedfde61b9360bc28456aa91ac773008 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 27 Oct 2021 15:26:10 +0300 Subject: [PATCH 157/303] Delete Legend config panel component --- .../home/components/home-components.module.ts | 2 - .../widget/legend-config-panel.component.html | 60 ---------- .../widget/legend-config-panel.component.scss | 32 ------ .../widget/legend-config-panel.component.ts | 105 ------------------ 4 files changed, 199 deletions(-) delete mode 100644 ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.html delete mode 100644 ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.scss delete mode 100644 ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.ts diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 71b983b4d4..5e0752fcbc 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -49,7 +49,6 @@ import { EntityAliasSelectComponent } from '@home/components/alias/entity-alias- import { DataKeysComponent } from '@home/components/widget/data-keys.component'; import { DataKeyConfigDialogComponent } from '@home/components/widget/data-key-config-dialog.component'; import { DataKeyConfigComponent } from '@home/components/widget/data-key-config.component'; -import { LegendConfigPanelComponent } from '@home/components/widget/legend-config-panel.component'; import { LegendConfigComponent } from '@home/components/widget/legend-config.component'; import { ManageWidgetActionsComponent } from '@home/components/widget/action/manage-widget-actions.component'; import { WidgetActionDialogComponent } from '@home/components/widget/action/widget-action-dialog.component'; @@ -182,7 +181,6 @@ import { DeviceProfileCommonModule } from '@home/components/profile/device/commo DataKeysComponent, DataKeyConfigComponent, DataKeyConfigDialogComponent, - LegendConfigPanelComponent, LegendConfigComponent, ManageWidgetActionsComponent, WidgetActionDialogComponent, diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.html deleted file mode 100644 index d88900f1a5..0000000000 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.html +++ /dev/null @@ -1,60 +0,0 @@ - -
    -
    -
    -
    -
    - - legend.direction - - - {{ legendDirectionTranslations.get(legendDirection[direction]) | translate }} - - - - - legend.position - - - {{ legendPositionTranslations.get(legendPosition[pos]) | translate }} - - - - - {{ 'legend.sort-legend' | translate }} - - - {{ 'legend.show-min' | translate }} - - - {{ 'legend.show-max' | translate }} - - - {{ 'legend.show-avg' | translate }} - - - {{ 'legend.show-total' | translate }} - -
    -
    -
    -
    -
    diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.scss deleted file mode 100644 index 1432b28318..0000000000 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.scss +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright © 2016-2021 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. - */ -:host { - width: 100%; - height: 100%; - form, - fieldset { - height: 100%; - } - - .mat-content { - overflow: hidden; - background-color: #fff; - } - - .mat-padding { - padding: 16px; - } -} diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.ts deleted file mode 100644 index c977155428..0000000000 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config-panel.component.ts +++ /dev/null @@ -1,105 +0,0 @@ -/// -/// Copyright © 2016-2021 The Thingsboard Authors -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// - -import { Component, Inject, InjectionToken, OnInit, ViewContainerRef } from '@angular/core'; -import { OverlayRef } from '@angular/cdk/overlay'; -import { PageComponent } from '@shared/components/page.component'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { - LegendConfig, - LegendDirection, - legendDirectionTranslationMap, - LegendPosition, - legendPositionTranslationMap -} from '@shared/models/widget.models'; - -export const LEGEND_CONFIG_PANEL_DATA = new InjectionToken('LegendConfigPanelData'); - -export interface LegendConfigPanelData { - legendConfig: LegendConfig; - legendConfigUpdated: (legendConfig: LegendConfig) => void; -} - -@Component({ - selector: 'tb-legend-config-panel', - templateUrl: './legend-config-panel.component.html', - styleUrls: ['./legend-config-panel.component.scss'] -}) -export class LegendConfigPanelComponent extends PageComponent implements OnInit { - - legendConfigForm: FormGroup; - - legendDirection = LegendDirection; - - legendDirections = Object.keys(LegendDirection); - - legendDirectionTranslations = legendDirectionTranslationMap; - - legendPosition = LegendPosition; - - legendPositions = Object.keys(LegendPosition); - - legendPositionTranslations = legendPositionTranslationMap; - - constructor(@Inject(LEGEND_CONFIG_PANEL_DATA) public data: LegendConfigPanelData, - public overlayRef: OverlayRef, - protected store: Store, - public fb: FormBuilder, - public viewContainerRef: ViewContainerRef) { - super(store); - } - - ngOnInit(): void { - this.legendConfigForm = this.fb.group({ - direction: [this.data.legendConfig.direction, []], - position: [this.data.legendConfig.position, []], - sortDataKeys: [this.data.legendConfig.sortDataKeys, []], - showMin: [this.data.legendConfig.showMin, []], - showMax: [this.data.legendConfig.showMax, []], - showAvg: [this.data.legendConfig.showAvg, []], - showTotal: [this.data.legendConfig.showTotal, []] - }); - this.legendConfigForm.get('direction').valueChanges.subscribe((direction: LegendDirection) => { - this.onDirectionChanged(direction); - }); - this.onDirectionChanged(this.data.legendConfig.direction); - this.legendConfigForm.valueChanges.subscribe(() => { - this.update(); - }); - } - - private onDirectionChanged(direction: LegendDirection) { - if (direction === LegendDirection.row) { - let position: LegendPosition = this.legendConfigForm.get('position').value; - if (position !== LegendPosition.bottom && position !== LegendPosition.top) { - position = LegendPosition.bottom; - } - this.legendConfigForm.patchValue( - { - position - }, {emitEvent: false} - ); - } - } - - update() { - const newLegendConfig: LegendConfig = this.legendConfigForm.value; - this.data.legendConfigUpdated(newLegendConfig); - } - -} From f4e864608e7cd24e6f43a1ff71060756aa30e758 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 27 Oct 2021 16:34:37 +0300 Subject: [PATCH 158/303] HTTP/2 configuration support --- application/src/main/resources/thingsboard.yml | 4 ++++ transport/http/src/main/resources/tb-http-transport.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 66aa79035c..6644e1b62e 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -47,6 +47,10 @@ server: key_alias: "${SSL_KEY_ALIAS:tomcat}" # Password used to access the key key_password: "${SSL_KEY_PASSWORD:thingsboard}" + # HTTP/2 support (takes effect only if server SSL is enabled) + http2: + # Enable/disable HTTP/2 support + enabled: "${HTTP2_ENABLED:true}" log_controller_error_stack_trace: "${HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE:false}" ws: send_timeout: "${TB_SERVER_WS_SEND_TIMEOUT:5000}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 603698c2df..17d86b0ea6 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -47,6 +47,10 @@ server: key_alias: "${SSL_KEY_ALIAS:tomcat}" # Password used to access the key key_password: "${SSL_KEY_PASSWORD:thingsboard}" + # HTTP/2 support (takes effect only if server SSL is enabled) + http2: + # Enable/disable HTTP/2 support + enabled: "${HTTP2_ENABLED:true}" # Zookeeper connection parameters. Used for service discovery. zk: From dda06bd0a18288b23a53c13616763f8cab428cd5 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 27 Oct 2021 17:00:00 +0300 Subject: [PATCH 159/303] process update credentials event for lwm2m transport --- .../device/DeviceActorMessageProcessor.java | 4 +- .../lwm2m/secure/TbLwM2MAuthorizer.java | 17 +++---- .../server/client/LwM2mClientContext.java | 2 - .../server/client/LwM2mClientContextImpl.java | 5 -- .../uplink/DefaultLwM2MUplinkMsgHandler.java | 51 ++++++++----------- 5 files changed, 31 insertions(+), 48 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index a12887db81..41d99a682b 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -719,7 +719,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { void processCredentialsUpdate(TbActorMsg msg) { if (((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials().getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { sessions.forEach((k, v) -> { - notifyTransportAboutProfileUpdate(k, v, ((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials()); + notifyTransportAboutDeviceCredentialsUpdate(k, v, ((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials()); }); } else { sessions.forEach((sessionId, sessionMd) -> notifyTransportAboutClosedSession(sessionId, sessionMd, "device credentials updated!")); @@ -747,7 +747,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); } - void notifyTransportAboutProfileUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { + void notifyTransportAboutDeviceCredentialsUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { ToTransportUpdateCredentialsProto.Builder notification = ToTransportUpdateCredentialsProto.newBuilder(); notification.addCredentialsId(deviceCredentials.getCredentialsId()); notification.addCredentialsValue(deviceCredentials.getCredentialsValue()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java index 04c6a2b160..bd08aa44eb 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java @@ -28,7 +28,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; -import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; @Component @RequiredArgsConstructor @@ -37,7 +37,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; public class TbLwM2MAuthorizer implements Authorizer { private final TbLwM2MDtlsSessionStore sessionStorage; - private final TbSecurityStore securityStore; + private final TbMainSecurityStore securityStore; private final SecurityChecker securityChecker = new SecurityChecker(); private final LwM2mClientContext clientContext; @@ -58,17 +58,16 @@ public class TbLwM2MAuthorizer implements Authorizer { // If session info is not found, this may be the trusted certificate, so we still need to check all other options below. } SecurityInfo expectedSecurityInfo = null; - if (securityStore != null) { - try { - expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint()); - } catch (LwM2MAuthException e) { - log.info("Registration failed: FORBIDDEN, endpointId: [{}]", registration.getEndpoint()); - return null; - } + try { + expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint()); + } catch (LwM2MAuthException e) { + log.info("Registration failed: FORBIDDEN, endpointId: [{}]", registration.getEndpoint()); + return null; } if (securityChecker.checkSecurityInfo(registration.getEndpoint(), senderIdentity, expectedSecurityInfo)) { return registration; } else { + securityStore.remove(registration.getEndpoint(), registration.getId()); return null; } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index c05148017c..4df0dc5ec2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -57,8 +57,6 @@ public interface LwM2mClientContext { void update(LwM2mClient lwM2MClient); - void removeCredentials(TransportProtos.SessionInfoProto sessionInfo); - void sendMsgsAfterSleeping(LwM2mClient lwM2MClient); boolean isComposite(LwM2mClient client); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 185a81a840..f89edb6353 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -328,11 +328,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } } - @Override - public void removeCredentials(TransportProtos.SessionInfoProto sessionInfo) { - //TODO: implement - } - @Override public void sendMsgsAfterSleeping(LwM2mClient lwM2MClient) { if (LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 0fb186a25d..cc57f14d78 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -28,12 +28,10 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.observation.Observation; -import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.request.ObserveRequest; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.request.WriteRequest; -import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ObserveResponse; import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadResponse; @@ -77,7 +75,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObser import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverRequest; -import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MLatchCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest; @@ -89,6 +86,7 @@ import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogServic import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2mSecurityStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; @@ -135,8 +133,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl public LwM2mValueConverterImpl converter; - private static final String REBOOT_ID = "/3/0/4"; - private final TransportService transportService; private final LwM2mTransportContext context; private final LwM2MAttributesService attributesService; @@ -150,6 +146,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl private final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; private final LwM2mVersionedModelProvider modelProvider; private final RegistrationStore registrationStore; + private final TbLwM2mSecurityStore securityStore; public DefaultLwM2MUplinkMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, @@ -163,7 +160,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl LwM2mTransportContext context, TbLwM2MDtlsSessionStore sessionStore, LwM2mVersionedModelProvider modelProvider, - RegistrationStore registrationStore) { + RegistrationStore registrationStore, TbLwM2mSecurityStore securityStore) { this.transportService = transportService; this.sessionManager = sessionManager; this.attributesService = attributesService; @@ -177,6 +174,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl this.sessionStore = sessionStore; this.modelProvider = modelProvider; this.registrationStore = registrationStore; + this.securityStore = securityStore; } @PostConstruct @@ -282,15 +280,12 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * @param observations - !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect */ public void unReg(Registration registration, Collection observations) { - executor.submit(() -> { - LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); - logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration"); - doUnReg(registration, client); - }); + executor.submit(() -> doUnReg(registration, clientContext.getClientByEndpoint(registration.getEndpoint()))); } private void doUnReg(Registration registration, LwM2mClient client) { try { + logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration"); clientContext.unregister(client, registration); SessionInfoProto sessionInfo = client.getSession(); if (sessionInfo != null) { @@ -405,23 +400,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onDeviceDelete(DeviceId deviceId) { - LwM2mClient client = clientContext.getClientByDeviceId(deviceId.getId()); - TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(REBOOT_ID).timeout(clientContext.getRequestTimeout(client)).build(); - defaultLwM2MDownlinkMsgHandler.sendExecuteRequest(client, request, new DownlinkRequestCallback<>() { - @Override - public void onSuccess(ExecuteRequest request, ExecuteResponse response) { - } - - @Override - public void onValidationError(String params, String msg) { - } - - @Override - public void onError(String params, Exception e) { - } - }); - registrationStore.removeRegistration(client.getRegistration().getId()); - doUnReg(client.getRegistration(), client); + clearAndUnregister(clientContext.getClientByDeviceId(deviceId.getId())); } @Override @@ -920,8 +899,8 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl */ @Override public void onToTransportUpdateCredentials(SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials) { - log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList()); - this.clientContext.removeCredentials(sessionInfo); + log.info("[{}] updateCredentials", sessionInfo); + clearAndUnregister(clientContext.getClientBySessionInfo(sessionInfo)); } /** @@ -998,4 +977,16 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl .setLastActivityTime(System.currentTimeMillis()) .build(), TransportServiceCallback.EMPTY); } + + private void clearAndUnregister(LwM2mClient client) { + client.lock(); + try { + Registration registration = client.getRegistration(); + doUnReg(registration, client); + securityStore.remove(registration.getEndpoint(), registration.getId()); + registrationStore.removeRegistration(registration.getId()); + } finally { + client.unlock(); + } + } } From b84c6abd10141c389f5657cb0c86f6498509d8a8 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 27 Oct 2021 17:09:41 +0300 Subject: [PATCH 160/303] refactoring --- .../transport/lwm2m/server/LwM2mSessionMsgListener.java | 6 +----- .../lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java index fddd2a24fb..3e0ad17925 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java @@ -112,10 +112,6 @@ public class LwM2mSessionMsgListener implements GenericFutureListener Date: Wed, 27 Oct 2021 19:12:23 +0300 Subject: [PATCH 161/303] Change position advanced settings and add lazy loadin for expansion panel --- .../widget/widget-config.component.html | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 7e69ca704a..4f379d95d4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -310,21 +310,6 @@
    - - - - widget-config.advanced-settings - - -
    - -
    -
    widget-config.title-icon @@ -347,6 +332,21 @@
    + + + + widget-config.advanced-settings + + + + + +
    widget-config.widget-style @@ -391,14 +391,14 @@ widget-config.advanced-settings -
    + -
    +
    @@ -414,7 +414,9 @@ widget-config.advanced-settings - + + +
    @@ -430,17 +432,19 @@ widget-config.advanced-settings -
    - - widget-config.order - - - - widget-config.height - - -
    + +
    + + widget-config.order + + + + widget-config.height + + +
    +
    Date: Thu, 28 Oct 2021 09:57:34 +0300 Subject: [PATCH 162/303] Add function onDirection Change for Legend --- .../components/widget/legend-config.component.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts index d4ec111bb9..eb38e0adb1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts @@ -76,6 +76,20 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc showAvg: [null, []], showTotal: [null, []] }); + this.legendConfigForm.get('direction').valueChanges.subscribe((direction: LegendDirection) => { + this.onDirectionChanged(direction); + }); + } + + private onDirectionChanged(direction: LegendDirection) { + if (direction === LegendDirection.row) { + let position: LegendPosition = this.legendConfigForm.get('position').value; + if (position !== LegendPosition.bottom && position !== LegendPosition.top) { + position = LegendPosition.bottom; + } + this.legendConfigForm.patchValue({position}, {emitEvent: false} + ); + } } ngOnDestroy(): void { @@ -125,6 +139,7 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc showTotal: isDefined(this.legendSettings.showTotal) ? this.legendSettings.showTotal : false }); } + this.onDirectionChanged(this.legendSettings.direction); this.createChangeSubscriptions(); } From 560e3fe1dfb08dc3decd30733dc6814a23bb374e Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 28 Oct 2021 10:18:58 +0300 Subject: [PATCH 163/303] Disable icon title click event --- .../material-icon-select.component.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.ts b/ui-ngx/src/app/shared/components/material-icon-select.component.ts index 5878751ac9..12f7e3f11f 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.ts +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.ts @@ -92,14 +92,16 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit } openIconDialog() { - this.dialogs.materialIconPicker(this.materialIconFormGroup.get('icon').value).subscribe( - (icon) => { - if (icon) { - this.materialIconFormGroup.patchValue( - {icon}, {emitEvent: true} - ); + if (!this.disabled) { + this.dialogs.materialIconPicker(this.materialIconFormGroup.get('icon').value).subscribe( + (icon) => { + if (icon) { + this.materialIconFormGroup.patchValue( + {icon}, {emitEvent: true} + ); + } } - } - ); + ); + } } } From 6f4d837a7e930f1aa43630cd1eadc0bb23281b59 Mon Sep 17 00:00:00 2001 From: Artem Babak Date: Thu, 28 Oct 2021 10:20:50 +0300 Subject: [PATCH 164/303] Added license header --- .../components/protobuf-content.component.html | 17 +++++++++++++++++ .../components/protobuf-content.component.scss | 15 +++++++++++++++ .../components/protobuf-content.component.ts | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.html b/ui-ngx/src/app/shared/components/protobuf-content.component.html index b1ec6c8dd4..23a16ece43 100644 --- a/ui-ngx/src/app/shared/components/protobuf-content.component.html +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.html @@ -1,3 +1,20 @@ +
    diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.scss b/ui-ngx/src/app/shared/components/protobuf-content.component.scss index b2ebc9bbe6..369d172491 100644 --- a/ui-ngx/src/app/shared/components/protobuf-content.component.scss +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.scss @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2021 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. + */ :host { position: relative; diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.ts b/ui-ngx/src/app/shared/components/protobuf-content.component.ts index d3599fc6c3..0c1e7c7fac 100644 --- a/ui-ngx/src/app/shared/components/protobuf-content.component.ts +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.ts @@ -1,3 +1,19 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + import { Component, ElementRef, From e196150d3c672bd14e31271d428ed0bcd8040aba Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 28 Oct 2021 11:21:03 +0300 Subject: [PATCH 165/303] Transfer units and dicimals fields to data tab --- .../widget/widget-config.component.html | 31 ++++++++++++------- .../assets/locale/locale.constant-en_US.json | 5 +-- .../assets/locale/locale.constant-ru_RU.json | 3 +- .../assets/locale/locale.constant-uk_UA.json | 3 +- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 4f379d95d4..0121b07cf6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -290,6 +290,26 @@
    +
    + + + widget-config.data-settings + + +
    + + widget-config.units + + + + widget-config.decimals + + +
    +
    +
    +
    @@ -447,17 +467,6 @@ -
    - - widget-config.units - - - - widget-config.decimals - - -
    diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index dd719d3258..7451e2c1b9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3028,7 +3028,7 @@ "general-settings": "General settings", "display-title": "Display widget title", "drop-shadow": "Drop shadow", - "enable-fullscreen": "Allow fullscreen", + "enable-fullscreen": "Enable fullscreen", "background-color": "Background color", "text-color": "Text color", "padding": "Padding", @@ -3076,7 +3076,8 @@ "display-icon": "Display title icon", "icon-color": "Icon color", "icon-size": "Icon size", - "advanced-settings": "Advanced settings" + "advanced-settings": "Advanced settings", + "data-settings": "Data settings" }, "widget-type": { "import": "Import widget type", diff --git a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json index 65381458ce..d6fefd0e55 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json @@ -1678,7 +1678,8 @@ "display-icon": "Показывать иконку в названии виджета", "icon-color": "Цвет иконки", "icon-size": "Размер иконки", - "advanced-settings": "Расширенные настройки" + "advanced-settings": "Расширенные настройки", + "data-settings": "Настройки данных" }, "widget-type": { "import": "Импортировать тип виджета", diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index b4620a937d..0031ca2ad0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -2250,7 +2250,8 @@ "display-icon": "Показувати іконку у назві віджету", "icon-color": "Колір іконки", "icon-size": "Розмір іконки", - "advanced-settings": "Розширені налаштування" + "advanced-settings": "Розширені налаштування", + "data-settings": "Налаштування даних" }, "widget-type": { "import": "Імпортувати тип віджета", From 79df8efeb746189b553aed3b1b03fa1573c6ca52 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 28 Oct 2021 11:34:39 +0300 Subject: [PATCH 166/303] fixed NPE --- .../thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java index 196dd1feb7..0a1cca72d9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java @@ -138,7 +138,11 @@ public class TbSendRPCRequestNode implements TbNode { } private String parseJsonData(JsonElement paramsEl) { - return paramsEl.isJsonPrimitive() ? paramsEl.getAsString() : gson.toJson(paramsEl); + if (paramsEl != null) { + return paramsEl.isJsonPrimitive() ? paramsEl.getAsString() : gson.toJson(paramsEl); + } else { + return null; + } } } From ec8808c9205c9265fc135defe7707f25d0ff56d3 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 28 Oct 2021 13:36:03 +0300 Subject: [PATCH 167/303] updated mqtt transport tests --- .../mqtt/AbstractMqttIntegrationTest.java | 21 +- ...AbstractMqttAttributesIntegrationTest.java | 588 ++++++++++++++++++ ...tBackwardCompatibilityIntegrationTest.java | 94 +++ ...tMqttAttributesRequestIntegrationTest.java | 110 +--- ...tAttributesRequestJsonIntegrationTest.java | 11 +- ...AttributesRequestProtoIntegrationTest.java | 213 +------ ...tBackwardCompatibilityIntegrationTest.java | 23 + ...MqttAttributesRequestIntegrationTest.java} | 2 +- ...AttributesRequestJsonIntegrationTest.java} | 2 +- ...ttributesRequestProtoIntegrationTest.java} | 2 +- ...sBackwardCompatibilityIntegrationTest.java | 69 ++ ...tMqttAttributesUpdatesIntegrationTest.java | 132 +--- ...tAttributesUpdatesJsonIntegrationTest.java | 16 +- ...AttributesUpdatesProtoIntegrationTest.java | 113 +--- ...sBackwardCompatibilityIntegrationTest.java | 23 + ...MqttAttributesUpdatesIntegrationTest.java} | 2 +- ...AttributesUpdatesJsonIntegrationTest.java} | 2 +- ...ttributesUpdatesProtoIntegrationTest.java} | 2 +- ...tClaimBackwardCompatibilityDeviceTest.java | 50 ++ .../claim/AbstractMqttClaimDeviceTest.java | 33 + .../AbstractMqttClaimProtoDeviceTest.java | 30 +- ...tClaimDeviceBackwardCompatibilityTest.java | 24 + ...Test.java => MqttClaimDeviceJsonTest.java} | 2 +- ...est.java => MqttClaimDeviceProtoTest.java} | 2 +- ...eSqlTest.java => MqttClaimDeviceTest.java} | 2 +- .../AbstractMqttProvisionJsonDeviceTest.java | 14 +- .../AbstractMqttProvisionProtoDeviceTest.java | 14 +- ....java => MqttProvisionDeviceJsonTest.java} | 2 +- ...java => MqttProvisionDeviceProtoTest.java} | 2 +- ...cBackwardCompatibilityIntegrationTest.java | 94 +++ ...ttServerSideRpcDefaultIntegrationTest.java | 10 +- ...tractMqttServerSideRpcIntegrationTest.java | 246 +++++++- ...tMqttServerSideRpcJsonIntegrationTest.java | 12 +- ...MqttServerSideRpcProtoIntegrationTest.java | 147 +---- ...cBackwardCompatibilityIntegrationTest.java | 24 + ... => MqttServerSideRpcIntegrationTest.java} | 2 +- ...MqttServerSideRpcJsonIntegrationTest.java} | 2 +- ...qttServerSideRpcProtoIntegrationTest.java} | 2 +- ...actMqttAttributesProtoIntegrationTest.java | 6 + ...ava => MqttAttributesIntegrationTest.java} | 2 +- ...=> MqttAttributesJsonIntegrationTest.java} | 2 +- ...> MqttAttributesProtoIntegrationTest.java} | 2 +- ...actMqttTimeseriesProtoIntegrationTest.java | 17 +- 43 files changed, 1396 insertions(+), 772 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java rename application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/{MqttAttributesRequestSqlIntegrationTest.java => MqttAttributesRequestIntegrationTest.java} (88%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/{MqttAttributesRequestJsonSqlIntegrationTest.java => MqttAttributesRequestJsonIntegrationTest.java} (88%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/{MqttAttributesRequestProtoSqlIntegrationTest.java => MqttAttributesRequestProtoIntegrationTest.java} (88%) create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java rename application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/{MqttAttributesUpdatesSqlIntegrationTest.java => MqttAttributesUpdatesIntegrationTest.java} (88%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/{MqttAttributesUpdatesSqlJsonIntegrationTest.java => MqttAttributesUpdatesJsonIntegrationTest.java} (88%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/{MqttAttributesUpdatesSqlProtoIntegrationTest.java => MqttAttributesUpdatesProtoIntegrationTest.java} (88%) create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimBackwardCompatibilityDeviceTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceBackwardCompatibilityTest.java rename application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/{MqttClaimDeviceJsonSqlTest.java => MqttClaimDeviceJsonTest.java} (90%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/{MqttClaimDeviceProtoSqlTest.java => MqttClaimDeviceProtoTest.java} (90%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/{MqttClaimDeviceSqlTest.java => MqttClaimDeviceTest.java} (91%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/{MqttProvisionDeviceJsonSqlTest.java => MqttProvisionDeviceJsonTest.java} (90%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/{MqttProvisionDeviceProtoSqlTest.java => MqttProvisionDeviceProtoTest.java} (90%) create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java rename application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/{MqttServerSideRpcSqlIntegrationTest.java => MqttServerSideRpcIntegrationTest.java} (89%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/{MqttServerSideRpcJsonSqlIntegrationTest.java => MqttServerSideRpcJsonIntegrationTest.java} (88%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/{MqttServerSideRpcProtoSqlIntegrationTest.java => MqttServerSideRpcProtoIntegrationTest.java} (88%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/{MqttAttributesSqlIntegrationTest.java => MqttAttributesIntegrationTest.java} (90%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/{MqttAttributesSqlJsonIntegrationTest.java => MqttAttributesJsonIntegrationTest.java} (89%) rename application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/{MqttAttributesSqlProtoIntegrationTest.java => MqttAttributesProtoIntegrationTest.java} (89%) diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/AbstractMqttIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/AbstractMqttIntegrationTest.java index 0d11c9a773..d815e85990 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/AbstractMqttIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/AbstractMqttIntegrationTest.java @@ -61,8 +61,12 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg protected DeviceProfile deviceProfile; - protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception { - this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + protected void processBeforeTest(String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception { + this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); + } + + protected void processBeforeTest(String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic, boolean enableCompatibilityWithJsonPayloadFormat, boolean useJsonPayloadFormatForDefaultDownlinkTopics) throws Exception { + this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, enableCompatibilityWithJsonPayloadFormat, useJsonPayloadFormatForDefaultDownlinkTopics); } protected void processBeforeTest(String deviceName, @@ -76,8 +80,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg String rpcRequestProtoSchema, String provisionKey, String provisionSecret, - DeviceProfileProvisionType provisionType - ) throws Exception { + DeviceProfileProvisionType provisionType, + boolean enableCompatibilityWithJsonPayloadFormat, + boolean useJsonPayloadFormatForDefaultDownlinkTopics) throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); @@ -106,7 +111,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg gateway.setAdditionalInfo(additionalInfo); if (payloadType != null) { - DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, rpcResponseProtoSchema, rpcRequestProtoSchema, provisionKey, provisionSecret, provisionType); + DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, rpcResponseProtoSchema, rpcRequestProtoSchema, provisionKey, provisionSecret, provisionType, enableCompatibilityWithJsonPayloadFormat, useJsonPayloadFormatForDefaultDownlinkTopics); deviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class); device.setType(deviceProfile.getName()); device.setDeviceProfileId(deviceProfile.getId()); @@ -162,7 +167,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg String telemetryProtoSchema, String attributesProtoSchema, String rpcResponseProtoSchema, String rpcRequestProtoSchema, String provisionKey, String provisionSecret, - DeviceProfileProvisionType provisionType) { + DeviceProfileProvisionType provisionType, + boolean enableCompatibilityWithJsonPayloadFormat, + boolean useJsonPayloadFormatForDefaultDownlinkTopics) { DeviceProfile deviceProfile = new DeviceProfile(); deviceProfile.setName(transportPayloadType.name()); deviceProfile.setType(DeviceProfileType.DEFAULT); @@ -200,6 +207,8 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema); protoTransportPayloadConfiguration.setDeviceRpcResponseProtoSchema(rpcResponseProtoSchema); protoTransportPayloadConfiguration.setDeviceRpcRequestProtoSchema(rpcRequestProtoSchema); + protoTransportPayloadConfiguration.setEnableCompatibilityWithJsonPayloadFormat(enableCompatibilityWithJsonPayloadFormat); + protoTransportPayloadConfiguration.setUseJsonPayloadFormatForDefaultDownlinkTopics(enableCompatibilityWithJsonPayloadFormat && useJsonPayloadFormatForDefaultDownlinkTopics); transportPayloadTypeConfiguration = protoTransportPayloadConfiguration; } mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java index edbe2fcd28..8d2dce0bb9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java @@ -15,24 +15,72 @@ */ package org.thingsboard.server.transport.mqtt.attributes; +import com.github.os72.protobuf.dynamic.DynamicSchema; +import com.google.protobuf.Descriptors; +import com.google.protobuf.DynamicMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.squareup.wire.schema.internal.parser.ProtoFileElement; +import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.TransportPayloadType; +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; +import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @Slf4j public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqttIntegrationTest { + public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" + + "\n" + + "package test;\n" + + "\n" + + "message PostAttributes {\n" + + " string attribute1 = 1;\n" + + " bool attribute2 = 2;\n" + + " double attribute3 = 3;\n" + + " int32 attribute4 = 4;\n" + + " JsonObject attribute5 = 5;\n" + + "\n" + + " message JsonObject {\n" + + " int32 someNumber = 6;\n" + + " repeated int32 someArray = 7;\n" + + " NestedJsonObject someNestedObject = 8;\n" + + " message NestedJsonObject {\n" + + " string key = 9;\n" + + " }\n" + + " }\n" + + "}"; + protected static final String POST_ATTRIBUTES_PAYLOAD = "{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73," + "\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}"; + private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}"; + protected void processBeforeTest(String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception { super.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic); } @@ -107,4 +155,544 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt } } + // subscribe to attributes updates from server methods + + protected void processJsonTestSubscribeToAttributesUpdates(String attrSubTopic) throws Exception { + + MqttAsyncClient client = getMqttAsyncClient(accessToken); + + TestMqttCallback onUpdateCallback = getTestMqttCallback(); + client.setCallback(onUpdateCallback); + + client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()); + + Thread.sleep(1000); + + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS); + + validateUpdateAttributesJsonResponse(onUpdateCallback); + + TestMqttCallback onDeleteCallback = getTestMqttCallback(); + client.setCallback(onDeleteCallback); + + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class); + onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS); + + validateDeleteAttributesJsonResponse(onDeleteCallback); + } + + protected void processProtoTestSubscribeToAttributesUpdates(String attrSubTopic) throws Exception { + + MqttAsyncClient client = getMqttAsyncClient(accessToken); + + TestMqttCallback onUpdateCallback = getTestMqttCallback(); + client.setCallback(onUpdateCallback); + + client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()); + + Thread.sleep(1000); + + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS); + + validateUpdateAttributesProtoResponse(onUpdateCallback); + + TestMqttCallback onDeleteCallback = getTestMqttCallback(); + client.setCallback(onDeleteCallback); + + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class); + onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS); + + validateDeleteAttributesProtoResponse(onDeleteCallback); + } + + protected void validateUpdateAttributesJsonResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { + assertNotNull(callback.getPayloadBytes()); + String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); + assertEquals(JacksonUtil.toJsonNode(POST_ATTRIBUTES_PAYLOAD), JacksonUtil.toJsonNode(response)); + } + + protected void validateDeleteAttributesJsonResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { + assertNotNull(callback.getPayloadBytes()); + String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); + assertEquals(JacksonUtil.toJsonNode(RESPONSE_ATTRIBUTES_PAYLOAD_DELETED), JacksonUtil.toJsonNode(response)); + } + + protected void validateUpdateAttributesProtoResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { + assertNotNull(callback.getPayloadBytes()); + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); + List tsKvProtoList = getTsKvProtoList(); + attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList); + + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); + TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); + + List actualSharedUpdatedList = actualAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + List expectedSharedUpdatedList = expectedAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + + assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size()); + assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList)); + } + + protected void validateDeleteAttributesProtoResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { + assertNotNull(callback.getPayloadBytes()); + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); + attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5"); + + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); + TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); + + assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size()); + assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0)); + } + + protected void processJsonGatewayTestSubscribeToAttributesUpdates() throws Exception { + + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); + + TestMqttCallback onUpdateCallback = getTestMqttCallback(); + client.setCallback(onUpdateCallback); + + Device device = new Device(); + device.setName("Gateway Device Subscribe to attribute updates"); + device.setType("default"); + + byte[] connectPayloadBytes = getJsonConnectPayloadBytes(); + + publishMqttMsg(client, connectPayloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC); + + Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Subscribe to attribute updates", Device.class), + 20, + 100); + + assertNotNull(savedDevice); + + client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); + + Thread.sleep(1000); + + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS); + + validateJsonGatewayUpdateAttributesResponse(onUpdateCallback); + + TestMqttCallback onDeleteCallback = getTestMqttCallback(); + client.setCallback(onDeleteCallback); + + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class); + onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS); + + validateJsonGatewayDeleteAttributesResponse(onDeleteCallback); + + } + + protected void processProtoGatewayTestSubscribeToAttributesUpdates() throws Exception { + + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); + + TestMqttCallback onUpdateCallback = getTestMqttCallback(); + client.setCallback(onUpdateCallback); + + Device device = new Device(); + device.setName("Gateway Device Subscribe to attribute updates"); + device.setType("default"); + + byte[] connectPayloadBytes = getProtoConnectPayloadBytes(); + + publishMqttMsg(client, connectPayloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC); + + Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Subscribe to attribute updates", Device.class), + 20, + 100); + + assertNotNull(savedDevice); + + client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); + + Thread.sleep(1000); + + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS); + + validateProtoGatewayUpdateAttributesResponse(onUpdateCallback); + + TestMqttCallback onDeleteCallback = getTestMqttCallback(); + client.setCallback(onDeleteCallback); + + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class); + onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS); + + validateProtoGatewayDeleteAttributesResponse(onDeleteCallback); + + } + + protected void validateJsonGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { + assertNotNull(callback.getPayloadBytes()); + String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); + assertEquals(getJsonResponseGatewayAttributesUpdatedPayload(), s); + } + + protected void validateJsonGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { + assertNotNull(callback.getPayloadBytes()); + String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); + assertEquals(s, getJsonResponseGatewayAttributesDeletedPayload()); + } + + protected byte[] getJsonConnectPayloadBytes() { + String connectPayload = "{\"device\": \"Gateway Device Subscribe to attribute updates\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}"; + return connectPayload.getBytes(); + } + + private static String getJsonResponseGatewayAttributesUpdatedPayload() { + return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\"," + + "\"data\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; + } + + private static String getJsonResponseGatewayAttributesDeletedPayload() { + return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\",\"data\":{\"deleted\":[\"attribute5\"]}}"; + } + + protected void validateProtoGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { + assertNotNull(callback.getPayloadBytes()); + + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); + List tsKvProtoList = getTsKvProtoList(); + attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList); + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); + + TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder(); + gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates"); + gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(expectedAttributeUpdateNotificationMsg); + + TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build(); + TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); + + assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName()); + + List actualSharedUpdatedList = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + List expectedSharedUpdatedList = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + + assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size()); + assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList)); + + } + + protected void validateProtoGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { + assertNotNull(callback.getPayloadBytes()); + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); + attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5"); + TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); + + TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder(); + gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates"); + gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(attributeUpdateNotificationMsg); + + TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build(); + TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); + + assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName()); + + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg(); + TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg(); + + assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size()); + assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0)); + + } + + protected byte[] getProtoConnectPayloadBytes() { + TransportApiProtos.ConnectMsg connectProto = getConnectProto(); + return connectProto.toByteArray(); + } + + private TransportApiProtos.ConnectMsg getConnectProto() { + TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder(); + builder.setDeviceName("Gateway Device Subscribe to attribute updates"); + builder.setDeviceType(TransportPayloadType.PROTOBUF.name()); + return builder.build(); + } + + // request attributes from server methods + + protected void processJsonTestRequestAttributesValuesFromTheServer(String attrPubTopic, String attrSubTopic, String attrReqTopicPrefix) throws Exception { + + MqttAsyncClient client = getMqttAsyncClient(accessToken); + + postJsonAttributesAndSubscribeToTopic(savedDevice, client, attrPubTopic, attrSubTopic); + + Thread.sleep(5000); + + TestMqttCallback callback = getTestMqttCallback(); + client.setCallback(callback); + + validateJsonResponse(client, callback.getLatch(), callback, attrReqTopicPrefix); + } + + protected void processProtoTestRequestAttributesValuesFromTheServer(String attrPubTopic, String attrSubTopic, String attrReqTopicPrefix) throws Exception { + + MqttAsyncClient client = getMqttAsyncClient(accessToken); + + postProtoAttributesAndSubscribeToTopic(savedDevice, client, attrPubTopic, attrSubTopic); + + Thread.sleep(5000); + + TestMqttCallback callback = getTestMqttCallback(); + client.setCallback(callback); + + validateProtoResponse(client, callback.getLatch(), callback, attrReqTopicPrefix); + } + + protected void processJsonTestGatewayRequestAttributesValuesFromTheServer() throws Exception { + + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); + + postJsonGatewayDeviceClientAttributes(client); + + Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Request Attributes", Device.class), + 20, + 100); + + assertNotNull(savedDevice); + + Thread.sleep(2000); + + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + + Thread.sleep(5000); + + client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); + + TestMqttCallback clientAttributesCallback = getTestMqttCallback(); + client.setCallback(clientAttributesCallback); + validateJsonClientResponseGateway(client, clientAttributesCallback); + + TestMqttCallback sharedAttributesCallback = getTestMqttCallback(); + client.setCallback(sharedAttributesCallback); + validateJsonSharedResponseGateway(client, sharedAttributesCallback); + } + + protected void processProtoTestGatewayRequestAttributesValuesFromTheServer() throws Exception { + + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); + + postProtoGatewayDeviceClientAttributes(client); + + Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Request Attributes", Device.class), + 20, + 100); + + assertNotNull(savedDevice); + + Thread.sleep(2000); + + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + + Thread.sleep(5000); + + client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); + + TestMqttCallback clientAttributesCallback = getTestMqttCallback(); + client.setCallback(clientAttributesCallback); + validateProtoClientResponseGateway(client, clientAttributesCallback); + + TestMqttCallback sharedAttributesCallback = getTestMqttCallback(); + client.setCallback(sharedAttributesCallback); + validateProtoSharedResponseGateway(client, sharedAttributesCallback); + } + + protected void postJsonAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client, String attrPubTopic, String attrSubTopic) throws Exception { + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + client.publish(attrPubTopic, new MqttMessage(POST_ATTRIBUTES_PAYLOAD.getBytes())).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); + client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); + } + + protected void postProtoAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client, String attrPubTopic, String attrSubTopic) throws Exception { + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", AbstractMqttAttributesIntegrationTest.POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(ATTRIBUTES_SCHEMA_STR); + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA); + + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject"); + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType(); + assertNotNull(nestedJsonObjectBuilderDescriptor); + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build(); + + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject"); + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType(); + assertNotNull(jsonObjectBuilderDescriptor); + DynamicMessage jsonObject = jsonObjectBuilder + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42) + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1) + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2) + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3) + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject) + .build(); + + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes"); + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType(); + assertNotNull(postAttributesMsgDescriptor); + DynamicMessage postAttributesMsg = postAttributesBuilder + .setField(postAttributesMsgDescriptor.findFieldByName("attribute1"), "value1") + .setField(postAttributesMsgDescriptor.findFieldByName("attribute2"), true) + .setField(postAttributesMsgDescriptor.findFieldByName("attribute3"), 42.0) + .setField(postAttributesMsgDescriptor.findFieldByName("attribute4"), 73) + .setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject) + .build(); + byte[] payload = postAttributesMsg.toByteArray(); + client.publish(attrPubTopic, new MqttMessage(payload)); + client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()); + } + + protected void postJsonGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception { + String postClientAttributes = "{\"" + "Gateway Device Request Attributes" + "\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(postClientAttributes.getBytes())).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); + } + + protected void postProtoGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception { + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; + List expectedKeys = Arrays.asList(keys.split(",")); + TransportProtos.PostAttributeMsg postAttributeMsg = getPostAttributeMsg(expectedKeys); + TransportApiProtos.AttributesMsg.Builder attributesMsgBuilder = TransportApiProtos.AttributesMsg.newBuilder(); + attributesMsgBuilder.setDeviceName("Gateway Device Request Attributes"); + attributesMsgBuilder.setMsg(postAttributeMsg); + TransportApiProtos.AttributesMsg attributesMsg = attributesMsgBuilder.build(); + TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributeMsgBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); + gatewayAttributeMsgBuilder.addMsg(attributesMsg); + byte[] bytes = gatewayAttributeMsgBuilder.build().toByteArray(); + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(bytes)); + } + + protected void validateJsonResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback, String attrReqTopicPrefix) throws MqttException, InterruptedException, InvalidProtocolBufferException { + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; + String payloadStr = "{\"clientKeys\":\"" + keys + "\", \"sharedKeys\":\"" + keys + "\"}"; + MqttMessage mqttMessage = new MqttMessage(); + mqttMessage.setPayload(payloadStr.getBytes()); + client.publish(attrReqTopicPrefix + "1", mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); + latch.await(1, TimeUnit.MINUTES); + assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); + String expectedRequestPayload = "{\"client\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}},\"shared\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; + assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); + } + + protected void validateProtoResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback, String attrReqTopic) throws MqttException, InterruptedException, InvalidProtocolBufferException { + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; + TransportApiProtos.AttributesRequest.Builder attributesRequestBuilder = TransportApiProtos.AttributesRequest.newBuilder(); + attributesRequestBuilder.setClientKeys(keys); + attributesRequestBuilder.setSharedKeys(keys); + TransportApiProtos.AttributesRequest attributesRequest = attributesRequestBuilder.build(); + MqttMessage mqttMessage = new MqttMessage(); + mqttMessage.setPayload(attributesRequest.toByteArray()); + client.publish(attrReqTopic + "1", mqttMessage); + latch.await(3, TimeUnit.SECONDS); + assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); + TransportProtos.GetAttributeResponseMsg expectedAttributesResponse = getExpectedAttributeResponseMsg(); + TransportProtos.GetAttributeResponseMsg actualAttributesResponse = TransportProtos.GetAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); + assertEquals(expectedAttributesResponse.getRequestId(), actualAttributesResponse.getRequestId()); + List expectedClientKeyValueProtos = expectedAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + List expectedSharedKeyValueProtos = expectedAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + List actualClientKeyValueProtos = actualAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + List actualSharedKeyValueProtos = actualAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos)); + assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos)); + } + + private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() { + TransportProtos.GetAttributeResponseMsg.Builder result = TransportProtos.GetAttributeResponseMsg.newBuilder(); + List tsKvProtoList = getTsKvProtoList(); + result.addAllClientAttributeList(tsKvProtoList); + result.addAllSharedAttributeList(tsKvProtoList); + result.setRequestId(1); + return result.build(); + } + + protected void validateJsonClientResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { + String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": true, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}"; + MqttMessage mqttMessage = new MqttMessage(); + mqttMessage.setPayload(payloadStr.getBytes()); + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); + callback.getLatch().await(1, TimeUnit.MINUTES); + assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); + String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; + assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); + } + + protected void validateJsonSharedResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { + String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": false, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}"; + MqttMessage mqttMessage = new MqttMessage(); + mqttMessage.setPayload(payloadStr.getBytes()); + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); + callback.getLatch().await(1, TimeUnit.MINUTES); + assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); + String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; + assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); + } + + protected void validateProtoClientResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; + TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, true); + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray())); + callback.getLatch().await(3, TimeUnit.SECONDS); + assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); + TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(true); + TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); + assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName()); + + TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg(); + TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg(); + assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId()); + + List expectedClientKeyValueProtos = expectedResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + List actualClientKeyValueProtos = actualResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos)); + } + + protected void validateProtoSharedResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; + TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, false); + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray())); + callback.getLatch().await(3, TimeUnit.SECONDS); + assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); + TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(false); + TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); + assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName()); + + TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg(); + TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg(); + assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId()); + + List expectedSharedKeyValueProtos = expectedResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + List actualSharedKeyValueProtos = actualResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); + + assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos)); + } + + private TransportApiProtos.GatewayAttributeResponseMsg getExpectedGatewayAttributeResponseMsg(boolean client) { + TransportApiProtos.GatewayAttributeResponseMsg.Builder gatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.newBuilder(); + TransportProtos.GetAttributeResponseMsg.Builder getAttributeResponseMsgBuilder = TransportProtos.GetAttributeResponseMsg.newBuilder(); + List tsKvProtoList = getTsKvProtoList(); + if (client) { + getAttributeResponseMsgBuilder.addAllClientAttributeList(tsKvProtoList); + } else { + getAttributeResponseMsgBuilder.addAllSharedAttributeList(tsKvProtoList); + } + getAttributeResponseMsgBuilder.setRequestId(1); + TransportProtos.GetAttributeResponseMsg getAttributeResponseMsg = getAttributeResponseMsgBuilder.build(); + gatewayAttributeResponseMsg.setDeviceName("Gateway Device Request Attributes"); + gatewayAttributeResponseMsg.setResponseMsg(getAttributeResponseMsg); + return gatewayAttributeResponseMsg.build(); + } + + private TransportApiProtos.GatewayAttributesRequestMsg getGatewayAttributesRequestMsg(String keys, boolean client) { + return TransportApiProtos.GatewayAttributesRequestMsg.newBuilder() + .setClient(client) + .addAllKeys(Arrays.asList(keys.split(","))) + .setDeviceName("Gateway Device Request Attributes") + .setId(1).build(); + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest.java new file mode 100644 index 0000000000..b905d91a17 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest.java @@ -0,0 +1,94 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.attributes.request; + +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Test; +import org.thingsboard.server.common.data.DeviceProfileProvisionType; +import org.thingsboard.server.common.data.TransportPayloadType; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public abstract class AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest extends AbstractMqttAttributesIntegrationTest { + + @After + public void afterTest() throws Exception { + processAfterTest(); + } + + @Test + public void testRequestAttributesValuesFromTheServerWithEnabledJsonCompatibility() throws Exception { + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, true, false); + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); + } + + @Test + public void testRequestAttributesValuesFromTheServerWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); + } + + @Test + public void testRequestAttributesValuesFromTheServerOnShortTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX); + } + + @Test + public void testRequestAttributesValuesFromTheServerOnShortProtoTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_PROTO_TOPIC_PREFIX); + } + + @Test + public void testRequestAttributesValuesFromTheServerGatewayWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null, true, true); + processProtoTestGatewayRequestAttributesValuesFromTheServer(); + } + + @Test + public void testRequestAttributesValuesFromTheServerOnShortJsonTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null, true, true); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX); + } + + + protected List getKvProtos(List expectedKeys) { + List keyValueProtos = new ArrayList<>(); + TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V); + TransportProtos.KeyValueProto boolKeyValueProto = getKeyValueProto(expectedKeys.get(1), "true", TransportProtos.KeyValueType.BOOLEAN_V); + TransportProtos.KeyValueProto dblKeyValueProto = getKeyValueProto(expectedKeys.get(2), "42.0", TransportProtos.KeyValueType.DOUBLE_V); + TransportProtos.KeyValueProto longKeyValueProto = getKeyValueProto(expectedKeys.get(3), "73", TransportProtos.KeyValueType.LONG_V); + TransportProtos.KeyValueProto jsonKeyValueProto = getKeyValueProto(expectedKeys.get(4), "{\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}", TransportProtos.KeyValueType.JSON_V); + keyValueProtos.add(strKeyValueProto); + keyValueProtos.add(boolKeyValueProto); + keyValueProtos.add(dblKeyValueProto); + keyValueProtos.add(longKeyValueProto); + keyValueProtos.add(jsonKeyValueProto); + return keyValueProtos; + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java index c54e76e4a9..ea3c797b27 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java @@ -15,7 +15,11 @@ */ package org.thingsboard.server.transport.mqtt.attributes.request; +import com.github.os72.protobuf.dynamic.DynamicSchema; +import com.google.protobuf.Descriptors; +import com.google.protobuf.DynamicMessage; import com.google.protobuf.InvalidProtocolBufferException; +import com.squareup.wire.schema.internal.parser.ProtoFileElement; import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; @@ -25,16 +29,26 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; +import org.thingsboard.server.gen.transport.TransportApiProtos; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @Slf4j @@ -52,109 +66,21 @@ public abstract class AbstractMqttAttributesRequestIntegrationTest extends Abstr @Test public void testRequestAttributesValuesFromTheServer() throws Exception { - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerOnShortTopic() throws Exception { - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerOnShortJsonTopic() throws Exception { - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerGateway() throws Exception { - processTestGatewayRequestAttributesValuesFromTheServer(); - } - - protected void processTestRequestAttributesValuesFromTheServer(String attrPubTopic, String attrSubTopic, String attrReqTopicPrefix) throws Exception { - - MqttAsyncClient client = getMqttAsyncClient(accessToken); - - postAttributesAndSubscribeToTopic(savedDevice, client, attrPubTopic, attrSubTopic); - - Thread.sleep(5000); - - TestMqttCallback callback = getTestMqttCallback(); - client.setCallback(callback); - - validateResponse(client, callback.getLatch(), callback, attrReqTopicPrefix); - } - - protected void processTestGatewayRequestAttributesValuesFromTheServer() throws Exception { - - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); - - postGatewayDeviceClientAttributes(client); - - Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Request Attributes", Device.class), - 20, - 100); - - assertNotNull(savedDevice); - - Thread.sleep(2000); - - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); - - Thread.sleep(5000); - - client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); - - TestMqttCallback clientAttributesCallback = getTestMqttCallback(); - client.setCallback(clientAttributesCallback); - validateClientResponseGateway(client, clientAttributesCallback); - - TestMqttCallback sharedAttributesCallback = getTestMqttCallback(); - client.setCallback(sharedAttributesCallback); - validateSharedResponseGateway(client, sharedAttributesCallback); - } - - protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client, String attrPubTopic, String attrSubTopic) throws Exception { - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); - client.publish(attrPubTopic, new MqttMessage(POST_ATTRIBUTES_PAYLOAD.getBytes())).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); - client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); - } - - protected void postGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception { - String postClientAttributes = "{\"" + "Gateway Device Request Attributes" + "\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(postClientAttributes.getBytes())).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); - } - - protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback, String attrReqTopicPrefix) throws MqttException, InterruptedException, InvalidProtocolBufferException { - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; - String payloadStr = "{\"clientKeys\":\"" + keys + "\", \"sharedKeys\":\"" + keys + "\"}"; - MqttMessage mqttMessage = new MqttMessage(); - mqttMessage.setPayload(payloadStr.getBytes()); - client.publish(attrReqTopicPrefix + "1", mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); - latch.await(1, TimeUnit.MINUTES); - assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); - String expectedRequestPayload = "{\"client\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}},\"shared\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; - assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); - } - - protected void validateClientResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { - String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": true, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}"; - MqttMessage mqttMessage = new MqttMessage(); - mqttMessage.setPayload(payloadStr.getBytes()); - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); - callback.getLatch().await(1, TimeUnit.MINUTES); - assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); - String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; - assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); - } - - protected void validateSharedResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { - String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": false, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}"; - MqttMessage mqttMessage = new MqttMessage(); - mqttMessage.setPayload(payloadStr.getBytes()); - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1)); - callback.getLatch().await(1, TimeUnit.MINUTES); - assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); - String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; - assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); + processJsonTestGatewayRequestAttributesValuesFromTheServer(); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestJsonIntegrationTest.java index 2bd1877ee1..9bb6b45507 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestJsonIntegrationTest.java @@ -21,9 +21,10 @@ import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; @Slf4j -public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { +public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesIntegrationTest { @Before public void beforeTest() throws Exception { @@ -37,21 +38,21 @@ public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends A @Test public void testRequestAttributesValuesFromTheServer() throws Exception { - super.testRequestAttributesValuesFromTheServer(); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerOnShortTopic() throws Exception { - super.testRequestAttributesValuesFromTheServerOnShortTopic(); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerOnShortJsonTopic() throws Exception { - super.testRequestAttributesValuesFromTheServerOnShortJsonTopic(); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerGateway() throws Exception { - processTestGatewayRequestAttributesValuesFromTheServer(); + processJsonTestGatewayRequestAttributesValuesFromTheServer(); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestProtoIntegrationTest.java index 3015d91ffb..327819a8c5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestProtoIntegrationTest.java @@ -15,65 +15,20 @@ */ package org.thingsboard.server.transport.mqtt.attributes.request; -import com.github.os72.protobuf.dynamic.DynamicSchema; -import com.google.protobuf.Descriptors; -import com.google.protobuf.DynamicMessage; -import com.google.protobuf.InvalidProtocolBufferException; -import com.squareup.wire.schema.internal.parser.ProtoFileElement; -import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.MqttAsyncClient; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.eclipse.paho.client.mqttv3.MqttMessage; import org.junit.After; import org.junit.Test; -import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.TransportPayloadType; -import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.MqttTopics; -import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; -import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @Slf4j -public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { - - public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" + - "\n" + - "package test;\n" + - "\n" + - "message PostAttributes {\n" + - " string attribute1 = 1;\n" + - " bool attribute2 = 2;\n" + - " double attribute3 = 3;\n" + - " int32 attribute4 = 4;\n" + - " JsonObject attribute5 = 5;\n" + - "\n" + - " message JsonObject {\n" + - " int32 someNumber = 6;\n" + - " repeated int32 someArray = 7;\n" + - " NestedJsonObject someNestedObject = 8;\n" + - " message NestedJsonObject {\n" + - " string key = 9;\n" + - " }\n" + - " }\n" + - "}"; +public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesIntegrationTest { @After public void afterTest() throws Exception { @@ -83,182 +38,36 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends @Test public void testRequestAttributesValuesFromTheServer() throws Exception { super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", - TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED); - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerOnShortTopic() throws Exception { super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", - TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED); - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX); + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerOnShortProtoTopic() throws Exception { super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", - TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED); - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_PROTO_TOPIC_PREFIX); + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_PROTO_TOPIC_PREFIX); } @Test public void testRequestAttributesValuesFromTheServerGateway() throws Exception { super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null); - processTestGatewayRequestAttributesValuesFromTheServer(); + processProtoTestGatewayRequestAttributesValuesFromTheServer(); } @Test - public void testRequestAttributesValuesFromTheServerOnShortJsonTopic() throws Exception { } - - protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client, String attrPubTopic, String attrSubTopic) throws Exception { - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", AbstractMqttAttributesIntegrationTest.POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); - DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); - assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); - MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; - TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); - assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); - ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; - ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(ATTRIBUTES_SCHEMA_STR); - DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA); - - DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject"); - Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType(); - assertNotNull(nestedJsonObjectBuilderDescriptor); - DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build(); - - DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject"); - Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType(); - assertNotNull(jsonObjectBuilderDescriptor); - DynamicMessage jsonObject = jsonObjectBuilder - .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42) - .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1) - .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2) - .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3) - .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject) - .build(); - - DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes"); - Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType(); - assertNotNull(postAttributesMsgDescriptor); - DynamicMessage postAttributesMsg = postAttributesBuilder - .setField(postAttributesMsgDescriptor.findFieldByName("attribute1"), "value1") - .setField(postAttributesMsgDescriptor.findFieldByName("attribute2"), true) - .setField(postAttributesMsgDescriptor.findFieldByName("attribute3"), 42.0) - .setField(postAttributesMsgDescriptor.findFieldByName("attribute4"), 73) - .setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject) - .build(); - byte[] payload = postAttributesMsg.toByteArray(); - client.publish(attrPubTopic, new MqttMessage(payload)); - client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()); - } - - protected void postGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception { - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; - List expectedKeys = Arrays.asList(keys.split(",")); - TransportProtos.PostAttributeMsg postAttributeMsg = getPostAttributeMsg(expectedKeys); - TransportApiProtos.AttributesMsg.Builder attributesMsgBuilder = TransportApiProtos.AttributesMsg.newBuilder(); - attributesMsgBuilder.setDeviceName("Gateway Device Request Attributes"); - attributesMsgBuilder.setMsg(postAttributeMsg); - TransportApiProtos.AttributesMsg attributesMsg = attributesMsgBuilder.build(); - TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributeMsgBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); - gatewayAttributeMsgBuilder.addMsg(attributesMsg); - byte[] bytes = gatewayAttributeMsgBuilder.build().toByteArray(); - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(bytes)); - } - - protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback, String attrReqTopic) throws MqttException, InterruptedException, InvalidProtocolBufferException { - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; - TransportApiProtos.AttributesRequest.Builder attributesRequestBuilder = TransportApiProtos.AttributesRequest.newBuilder(); - attributesRequestBuilder.setClientKeys(keys); - attributesRequestBuilder.setSharedKeys(keys); - TransportApiProtos.AttributesRequest attributesRequest = attributesRequestBuilder.build(); - MqttMessage mqttMessage = new MqttMessage(); - mqttMessage.setPayload(attributesRequest.toByteArray()); - client.publish(attrReqTopic + "1", mqttMessage); - latch.await(3, TimeUnit.SECONDS); - assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); - TransportProtos.GetAttributeResponseMsg expectedAttributesResponse = getExpectedAttributeResponseMsg(); - TransportProtos.GetAttributeResponseMsg actualAttributesResponse = TransportProtos.GetAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); - assertEquals(expectedAttributesResponse.getRequestId(), actualAttributesResponse.getRequestId()); - List expectedClientKeyValueProtos = expectedAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - List expectedSharedKeyValueProtos = expectedAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - List actualClientKeyValueProtos = actualAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - List actualSharedKeyValueProtos = actualAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos)); - assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos)); - } - - protected void validateClientResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; - TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, true); - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray())); - callback.getLatch().await(3, TimeUnit.SECONDS); - assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); - TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(true); - TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); - assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName()); - - TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg(); - TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg(); - assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId()); - - List expectedClientKeyValueProtos = expectedResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - List actualClientKeyValueProtos = actualResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos)); - } - - protected void validateSharedResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; - TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, false); - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray())); - callback.getLatch().await(3, TimeUnit.SECONDS); - assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); - TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(false); - TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); - assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName()); - - TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg(); - TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg(); - assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId()); - - List expectedSharedKeyValueProtos = expectedResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - List actualSharedKeyValueProtos = actualResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - - assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos)); - } - - private TransportApiProtos.GatewayAttributesRequestMsg getGatewayAttributesRequestMsg(String keys, boolean client) { - return TransportApiProtos.GatewayAttributesRequestMsg.newBuilder() - .setClient(client) - .addAllKeys(Arrays.asList(keys.split(","))) - .setDeviceName("Gateway Device Request Attributes") - .setId(1).build(); - } - - private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() { - TransportProtos.GetAttributeResponseMsg.Builder result = TransportProtos.GetAttributeResponseMsg.newBuilder(); - List tsKvProtoList = getTsKvProtoList(); - result.addAllClientAttributeList(tsKvProtoList); - result.addAllSharedAttributeList(tsKvProtoList); - result.setRequestId(1); - return result.build(); + public void testRequestAttributesValuesFromTheServerOnShortJsonTopic() throws Exception { + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null); + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX); } - private TransportApiProtos.GatewayAttributeResponseMsg getExpectedGatewayAttributeResponseMsg(boolean client) { - TransportApiProtos.GatewayAttributeResponseMsg.Builder gatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.newBuilder(); - TransportProtos.GetAttributeResponseMsg.Builder getAttributeResponseMsgBuilder = TransportProtos.GetAttributeResponseMsg.newBuilder(); - List tsKvProtoList = getTsKvProtoList(); - if (client) { - getAttributeResponseMsgBuilder.addAllClientAttributeList(tsKvProtoList); - } else { - getAttributeResponseMsgBuilder.addAllSharedAttributeList(tsKvProtoList); - } - getAttributeResponseMsgBuilder.setRequestId(1); - TransportProtos.GetAttributeResponseMsg getAttributeResponseMsg = getAttributeResponseMsgBuilder.build(); - gatewayAttributeResponseMsg.setDeviceName("Gateway Device Request Attributes"); - gatewayAttributeResponseMsg.setResponseMsg(getAttributeResponseMsg); - return gatewayAttributeResponseMsg.build(); - } protected List getKvProtos(List expectedKeys) { List keyValueProtos = new ArrayList<>(); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java new file mode 100644 index 0000000000..166d2d7b14 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.attributes.request.sql; + +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest; + +@DaoSqlTest +public class MqttAttributesRequestBackwardCompatibilityIntegrationTest extends AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest { +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestIntegrationTest.java similarity index 88% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestIntegrationTest.java index 89253462f9..f56faeacac 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest; @DaoSqlTest -public class MqttAttributesRequestSqlIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { +public class MqttAttributesRequestIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonIntegrationTest.java similarity index 88% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonIntegrationTest.java index b6540832be..dbadaa4f1c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest; @DaoSqlTest -public class MqttAttributesRequestJsonSqlIntegrationTest extends AbstractMqttAttributesRequestJsonIntegrationTest { +public class MqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestJsonIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoIntegrationTest.java similarity index 88% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoIntegrationTest.java index 4615b75824..e1b58b9a5b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest; @DaoSqlTest -public class MqttAttributesRequestProtoSqlIntegrationTest extends AbstractMqttAttributesRequestProtoIntegrationTest { +public class MqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestProtoIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java new file mode 100644 index 0000000000..a54bbe3688 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java @@ -0,0 +1,69 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.attributes.updates; + +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Test; +import org.thingsboard.server.common.data.TransportPayloadType; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; + +@Slf4j +public abstract class AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest extends AbstractMqttAttributesIntegrationTest { + + @After + public void afterTest() throws Exception { + processAfterTest(); + } + + @Test + public void testSubscribeToAttributesUpdatesFromServerWithEnabledJsonCompatibility() throws Exception { + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, false); + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); + } + + @Test + public void testSubscribeToAttributesUpdatesFromServerWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, true); + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); + } + + @Test + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, true); + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC); + } + + @Test + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, true); + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC); + } + + @Test + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortProtoTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, true); + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC); + } + + @Test + public void testProtoSubscribeToAttributesUpdatesFromTheServerGatewayWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, false); + processProtoGatewayTestSubscribeToAttributesUpdates(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java index f179741abb..6973f7db8f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java @@ -15,40 +15,17 @@ */ package org.thingsboard.server.transport.mqtt.attributes.updates; -import com.google.protobuf.InvalidProtocolBufferException; -import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.profile.MqttTopics; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.TimeUnit; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @Slf4j public abstract class AbstractMqttAttributesUpdatesIntegrationTest extends AbstractMqttAttributesIntegrationTest { - private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}"; - - private static String getResponseGatewayAttributesUpdatedPayload() { - return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\"," + - "\"data\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; - } - - private static String getResponseGatewayAttributesDeletedPayload() { - return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\",\"data\":{\"deleted\":[\"attribute5\"]}}"; - } - @Before public void beforeTest() throws Exception { processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.JSON, null, null); @@ -60,116 +37,23 @@ public abstract class AbstractMqttAttributesUpdatesIntegrationTest extends Abstr } @Test - public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception { - processTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); + public void testJsonSubscribeToAttributesUpdatesFromTheServer() throws Exception { + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception { - processTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC); + public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception { + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception { - processTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC); + public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception { + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { - processGatewayTestSubscribeToAttributesUpdates(); - } - - protected void processTestSubscribeToAttributesUpdates(String attrSubTopic) throws Exception { - - MqttAsyncClient client = getMqttAsyncClient(accessToken); - - TestMqttCallback onUpdateCallback = getTestMqttCallback(); - client.setCallback(onUpdateCallback); - - client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()); - - Thread.sleep(1000); - - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); - onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS); - - validateUpdateAttributesResponse(onUpdateCallback); - - TestMqttCallback onDeleteCallback = getTestMqttCallback(); - client.setCallback(onDeleteCallback); - - doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class); - onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS); - - validateDeleteAttributesResponse(onDeleteCallback); - } - - protected void validateUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { - assertNotNull(callback.getPayloadBytes()); - String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); - assertEquals(JacksonUtil.toJsonNode(POST_ATTRIBUTES_PAYLOAD), JacksonUtil.toJsonNode(response)); - } - - protected void validateDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { - assertNotNull(callback.getPayloadBytes()); - String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); - assertEquals(JacksonUtil.toJsonNode(RESPONSE_ATTRIBUTES_PAYLOAD_DELETED), JacksonUtil.toJsonNode(response)); + public void testJsonSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { + processJsonGatewayTestSubscribeToAttributesUpdates(); } - protected void processGatewayTestSubscribeToAttributesUpdates() throws Exception { - - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); - - TestMqttCallback onUpdateCallback = getTestMqttCallback(); - client.setCallback(onUpdateCallback); - - Device device = new Device(); - device.setName("Gateway Device Subscribe to attribute updates"); - device.setType("default"); - - byte[] connectPayloadBytes = getConnectPayloadBytes(); - - publishMqttMsg(client, connectPayloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC); - - Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Subscribe to attribute updates", Device.class), - 20, - 100); - - assertNotNull(savedDevice); - - client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); - - Thread.sleep(1000); - - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); - onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS); - - validateGatewayUpdateAttributesResponse(onUpdateCallback); - - TestMqttCallback onDeleteCallback = getTestMqttCallback(); - client.setCallback(onDeleteCallback); - - doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class); - onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS); - - validateGatewayDeleteAttributesResponse(onDeleteCallback); - - } - - protected void validateGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { - assertNotNull(callback.getPayloadBytes()); - String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); - assertEquals(getResponseGatewayAttributesUpdatedPayload(), s); - } - - protected void validateGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { - assertNotNull(callback.getPayloadBytes()); - String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); - assertEquals(s, getResponseGatewayAttributesDeletedPayload()); - } - - protected byte[] getConnectPayloadBytes() { - String connectPayload = "{\"device\": \"Gateway Device Subscribe to attribute updates\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}"; - return connectPayload.getBytes(); - } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java index 4efadaccaa..7a8b28356c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java @@ -35,22 +35,22 @@ public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends A } @Test - public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception { - super.testSubscribeToAttributesUpdatesFromTheServer(); + public void testJsonSubscribeToAttributesUpdatesFromTheServer() throws Exception { + super.testJsonSubscribeToAttributesUpdatesFromTheServer(); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception { - super.testSubscribeToAttributesUpdatesFromTheServerOnShortTopic(); + public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception { + super.testJsonSubscribeToAttributesUpdatesFromTheServerOnShortTopic(); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception { - super.testSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic(); + public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception { + super.testJsonSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic(); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { - processGatewayTestSubscribeToAttributesUpdates(); + public void testJsonSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { + super.testJsonSubscribeToAttributesUpdatesFromTheServerGateway(); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesProtoIntegrationTest.java index 606e05930d..5c0bc631bb 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesProtoIntegrationTest.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; import java.util.List; import java.util.stream.Collectors; @@ -33,7 +34,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @Slf4j -public abstract class AbstractMqttAttributesUpdatesProtoIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { +public abstract class AbstractMqttAttributesUpdatesProtoIntegrationTest extends AbstractMqttAttributesIntegrationTest { @Before public void beforeTest() throws Exception { @@ -46,116 +47,28 @@ public abstract class AbstractMqttAttributesUpdatesProtoIntegrationTest extends } @Test - public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception { - super.testSubscribeToAttributesUpdatesFromTheServer(); + public void testProtoSubscribeToAttributesUpdatesFromTheServer() throws Exception { + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception { - super.testSubscribeToAttributesUpdatesFromTheServerOnShortTopic(); + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception { + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception {} - - @Test - public void testSubscribeToAttributesUpdatesFromTheServerOnShortProtoTopic() throws Exception { - processTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC); + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception { + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC); } @Test - public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { - processGatewayTestSubscribeToAttributesUpdates(); + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortProtoTopic() throws Exception { + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC); } - protected void validateUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { - assertNotNull(callback.getPayloadBytes()); - TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); - List tsKvProtoList = getTsKvProtoList(); - attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList); - - TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); - TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); - - List actualSharedUpdatedList = actualAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - List expectedSharedUpdatedList = expectedAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - - assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size()); - assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList)); - - } - - protected void validateDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { - assertNotNull(callback.getPayloadBytes()); - TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); - attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5"); - - TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); - TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); - - assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size()); - assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0)); - - } - - protected void validateGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { - assertNotNull(callback.getPayloadBytes()); - - TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); - List tsKvProtoList = getTsKvProtoList(); - attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList); - TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); - - TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder(); - gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates"); - gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(expectedAttributeUpdateNotificationMsg); - - TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build(); - TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); - - assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName()); - - List actualSharedUpdatedList = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - List expectedSharedUpdatedList = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); - - assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size()); - assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList)); - - } - - protected void validateGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { - assertNotNull(callback.getPayloadBytes()); - TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); - attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5"); - TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); - - TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder(); - gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates"); - gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(attributeUpdateNotificationMsg); - - TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build(); - TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); - - assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName()); - - TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg(); - TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg(); - - assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size()); - assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0)); - - } - - protected byte[] getConnectPayloadBytes() { - TransportApiProtos.ConnectMsg connectProto = getConnectProto(); - return connectProto.toByteArray(); - } - - private TransportApiProtos.ConnectMsg getConnectProto() { - TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder(); - builder.setDeviceName("Gateway Device Subscribe to attribute updates"); - builder.setDeviceType(TransportPayloadType.PROTOBUF.name()); - return builder.build(); + @Test + public void testProtoSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { + processProtoGatewayTestSubscribeToAttributesUpdates(); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java new file mode 100644 index 0000000000..94b0284ece --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.attributes.updates.sql; + +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest; + +@DaoSqlTest +public class MqttAttributesUpdatesBackwardCompatibilityIntegrationTest extends AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest { +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesIntegrationTest.java similarity index 88% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesIntegrationTest.java index 0f5dfdda46..fcc3dd0e92 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest; @DaoSqlTest -public class MqttAttributesUpdatesSqlIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { +public class MqttAttributesUpdatesIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesJsonIntegrationTest.java similarity index 88% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesJsonIntegrationTest.java index 54b5060886..51aaeb60d6 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesJsonIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest; @DaoSqlTest -public class MqttAttributesUpdatesSqlJsonIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest { +public class MqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesProtoIntegrationTest.java similarity index 88% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesProtoIntegrationTest.java index 68267bbd49..0139c7c547 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesProtoIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest; @DaoSqlTest -public class MqttAttributesUpdatesSqlProtoIntegrationTest extends AbstractMqttAttributesUpdatesProtoIntegrationTest { +public class MqttAttributesUpdatesProtoIntegrationTest extends AbstractMqttAttributesUpdatesProtoIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimBackwardCompatibilityDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimBackwardCompatibilityDeviceTest.java new file mode 100644 index 0000000000..2c0fa6c877 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimBackwardCompatibilityDeviceTest.java @@ -0,0 +1,50 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.claim; + +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.common.data.TransportPayloadType; + +@Slf4j +public abstract class AbstractMqttClaimBackwardCompatibilityDeviceTest extends AbstractMqttClaimDeviceTest { + + @Before + public void beforeTest() throws Exception { + processBeforeTest("Test Claim device", "Test Claim gateway", TransportPayloadType.PROTOBUF, null, null, true, true); + createCustomerAndUser(); + } + + @After + public void afterTest() throws Exception { super.afterTest(); } + + @Test + public void testGatewayClaimingDevice() throws Exception { + processTestGatewayClaimingDevice("Test claiming gateway device Proto", false); + } + + @Test + public void testGatewayClaimingDeviceWithoutSecretAndDuration() throws Exception { + processTestGatewayClaimingDevice("Test claiming gateway device empty payload Proto", true); + } + + protected void processTestGatewayClaimingDevice(String deviceName, boolean emptyPayload) throws Exception { + processProtoTestGatewayClaimDevice(deviceName, emptyPayload); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimDeviceTest.java index 6bbcf82e39..996e460f22 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimDeviceTest.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.device.claim.ClaimResponse; import org.thingsboard.server.dao.device.claim.ClaimResult; +import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; import static org.junit.Assert.assertEquals; @@ -202,4 +203,36 @@ public abstract class AbstractMqttClaimDeviceTest extends AbstractMqttIntegratio validateGatewayClaimResponse(deviceName, emptyPayload, client, failurePayloadBytes, payloadBytes); } + protected void processProtoTestGatewayClaimDevice(String deviceName, boolean emptyPayload) throws Exception { + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); + byte[] failurePayloadBytes; + byte[] payloadBytes; + if (emptyPayload) { + payloadBytes = getGatewayClaimMsg(deviceName, 0, emptyPayload).toByteArray(); + } else { + payloadBytes = getGatewayClaimMsg(deviceName, 60000, emptyPayload).toByteArray(); + } + failurePayloadBytes = getGatewayClaimMsg(deviceName, 1, emptyPayload).toByteArray(); + + validateGatewayClaimResponse(deviceName, emptyPayload, client, failurePayloadBytes, payloadBytes); + } + + private TransportApiProtos.GatewayClaimMsg getGatewayClaimMsg(String deviceName, long duration, boolean emptyPayload) { + TransportApiProtos.GatewayClaimMsg.Builder gatewayClaimMsgBuilder = TransportApiProtos.GatewayClaimMsg.newBuilder(); + TransportApiProtos.ClaimDeviceMsg.Builder claimDeviceMsgBuilder = TransportApiProtos.ClaimDeviceMsg.newBuilder(); + TransportApiProtos.ClaimDevice.Builder claimDeviceBuilder = TransportApiProtos.ClaimDevice.newBuilder(); + if (!emptyPayload) { + claimDeviceBuilder.setSecretKey("value"); + } + if (duration > 0) { + claimDeviceBuilder.setDurationMs(duration); + } + TransportApiProtos.ClaimDevice claimDevice = claimDeviceBuilder.build(); + claimDeviceMsgBuilder.setClaimRequest(claimDevice); + claimDeviceMsgBuilder.setDeviceName(deviceName); + TransportApiProtos.ClaimDeviceMsg claimDeviceMsg = claimDeviceMsgBuilder.build(); + gatewayClaimMsgBuilder.addMsg(claimDeviceMsg); + return gatewayClaimMsgBuilder.build(); + } + } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimProtoDeviceTest.java index c3a5fb8cbb..5dc5bcf8be 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimProtoDeviceTest.java @@ -68,35 +68,7 @@ public abstract class AbstractMqttClaimProtoDeviceTest extends AbstractMqttClaim } protected void processTestGatewayClaimingDevice(String deviceName, boolean emptyPayload) throws Exception { - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); - byte[] failurePayloadBytes; - byte[] payloadBytes; - if (emptyPayload) { - payloadBytes = getGatewayClaimMsg(deviceName, 0, emptyPayload).toByteArray(); - } else { - payloadBytes = getGatewayClaimMsg(deviceName, 60000, emptyPayload).toByteArray(); - } - failurePayloadBytes = getGatewayClaimMsg(deviceName, 1, emptyPayload).toByteArray(); - - validateGatewayClaimResponse(deviceName, emptyPayload, client, failurePayloadBytes, payloadBytes); - } - - private TransportApiProtos.GatewayClaimMsg getGatewayClaimMsg(String deviceName, long duration, boolean emptyPayload) { - TransportApiProtos.GatewayClaimMsg.Builder gatewayClaimMsgBuilder = TransportApiProtos.GatewayClaimMsg.newBuilder(); - TransportApiProtos.ClaimDeviceMsg.Builder claimDeviceMsgBuilder = TransportApiProtos.ClaimDeviceMsg.newBuilder(); - TransportApiProtos.ClaimDevice.Builder claimDeviceBuilder = TransportApiProtos.ClaimDevice.newBuilder(); - if (!emptyPayload) { - claimDeviceBuilder.setSecretKey("value"); - } - if (duration > 0) { - claimDeviceBuilder.setDurationMs(duration); - } - TransportApiProtos.ClaimDevice claimDevice = claimDeviceBuilder.build(); - claimDeviceMsgBuilder.setClaimRequest(claimDevice); - claimDeviceMsgBuilder.setDeviceName(deviceName); - TransportApiProtos.ClaimDeviceMsg claimDeviceMsg = claimDeviceMsgBuilder.build(); - gatewayClaimMsgBuilder.addMsg(claimDeviceMsg); - return gatewayClaimMsgBuilder.build(); + processProtoTestGatewayClaimDevice(deviceName, emptyPayload); } private TransportApiProtos.ClaimDevice getClaimDevice(long duration, boolean emptyPayload) { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceBackwardCompatibilityTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceBackwardCompatibilityTest.java new file mode 100644 index 0000000000..3135aa951c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceBackwardCompatibilityTest.java @@ -0,0 +1,24 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.claim.sql; + +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimBackwardCompatibilityDeviceTest; +import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimDeviceTest; + +@DaoSqlTest +public class MqttClaimDeviceBackwardCompatibilityTest extends AbstractMqttClaimBackwardCompatibilityDeviceTest { +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonSqlTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonTest.java similarity index 90% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonSqlTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonTest.java index 18d504f94c..6206f9dc2b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimJsonDeviceTest; @DaoSqlTest -public class MqttClaimDeviceJsonSqlTest extends AbstractMqttClaimJsonDeviceTest { +public class MqttClaimDeviceJsonTest extends AbstractMqttClaimJsonDeviceTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoSqlTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoTest.java similarity index 90% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoSqlTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoTest.java index fd3595f543..4c35df2e7a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimProtoDeviceTest; @DaoSqlTest -public class MqttClaimDeviceProtoSqlTest extends AbstractMqttClaimProtoDeviceTest { +public class MqttClaimDeviceProtoTest extends AbstractMqttClaimProtoDeviceTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceSqlTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceTest.java similarity index 91% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceSqlTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceTest.java index 666c51394d..3ab5c72f43 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimDeviceTest; @DaoSqlTest -public class MqttClaimDeviceSqlTest extends AbstractMqttClaimDeviceTest { +public class MqttClaimDeviceTest extends AbstractMqttClaimDeviceTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java index 870b62b195..f2aef88273 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java @@ -94,7 +94,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn protected void processTestProvisioningDisabledDevice() throws Exception { - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); byte[] result = createMqttClientAndPublish().getPayloadBytes(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); @@ -103,7 +103,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false); byte[] result = createMqttClientAndPublish().getPayloadBytes(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); @@ -119,7 +119,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false); String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\""; byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); @@ -138,7 +138,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception { - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false); String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\""; byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); @@ -163,7 +163,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception { - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false); String requestCredentials = ",\"credentialsType\": \"MQTT_BASIC\",\"clientId\": \"test_clientId\",\"username\": \"test_username\",\"password\": \"test_password\""; byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); @@ -188,7 +188,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn } protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception { - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, false, false); byte[] result = createMqttClientAndPublish().getPayloadBytes(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); @@ -199,7 +199,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn } protected void processTestProvisioningWithBadKeyDevice() throws Exception { - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, false, false); byte[] result = createMqttClientAndPublish().getPayloadBytes(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java index 97ebbfe4a7..bfa4f6badf 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java @@ -101,14 +101,14 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI protected void processTestProvisioningDisabledDevice() throws Exception { - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); Assert.assertNotNull(result); Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString()); } protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); @@ -122,7 +122,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI } protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null,null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null,null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false); CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build(); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayloadBytes()); @@ -140,7 +140,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI } protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception { - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false); CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build(); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayloadBytes()); @@ -164,7 +164,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI } protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception { - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false); CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateBasicMqttCredRequestMsg( ValidateBasicMqttCredRequestMsg.newBuilder() .setClientId("test_clientId") @@ -195,7 +195,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI } protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception { - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, false, false); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId()); @@ -205,7 +205,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI } protected void processTestProvisioningWithBadKeyDevice() throws Exception { - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, false, false); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString()); } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonSqlTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonTest.java similarity index 90% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonSqlTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonTest.java index bca75c87b2..5cb9ae345a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.provision.AbstractMqttProvisionJsonDeviceTest; @DaoSqlTest -public class MqttProvisionDeviceJsonSqlTest extends AbstractMqttProvisionJsonDeviceTest { +public class MqttProvisionDeviceJsonTest extends AbstractMqttProvisionJsonDeviceTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoSqlTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoTest.java similarity index 90% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoSqlTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoTest.java index 62cb3d4779..1e32fab350 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.provision.AbstractMqttProvisionProtoDeviceTest; @DaoSqlTest -public class MqttProvisionDeviceProtoSqlTest extends AbstractMqttProvisionProtoDeviceTest { +public class MqttProvisionDeviceProtoTest extends AbstractMqttProvisionProtoDeviceTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest.java new file mode 100644 index 0000000000..f8b3949b60 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest.java @@ -0,0 +1,94 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.rpc; + +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.common.data.DeviceProfileProvisionType; +import org.thingsboard.server.common.data.TransportPayloadType; +import org.thingsboard.server.common.data.device.profile.MqttTopics; + +@Slf4j +public abstract class AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest { + + @After + public void afterTest() throws Exception { + super.processAfterTest(); + } + + @Test + public void testServerMqttOneWayRpcWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processOneWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); + } + + @Test + public void testServerMqttOneWayRpcOnShortTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processOneWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC); + } + + @Test + public void testServerMqttOneWayRpcOnShortProtoTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processOneWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC); + } + + @Test + public void testServerMqttTwoWayRpcWithEnabledJsonCompatibility() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, false); + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); + } + + @Test + public void testServerMqttTwoWayRpcWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); + } + + @Test + public void testServerMqttTwoWayRpcOnShortTopic() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC); + } + + @Test + public void testServerMqttTwoWayRpcOnShortProtoTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC); + } + + @Test + public void testServerMqttTwoWayRpcOnShortJsonTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC); + } + + @Test + public void testGatewayServerMqttOneWayRpcWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processProtoOneWayRpcTestGateway("Gateway Device OneWay RPC Proto"); + } + + @Test + public void testGatewayServerMqttTwoWayRpcWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception { + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true); + processProtoTwoWayRpcTestGateway("Gateway Device TwoWay RPC Proto"); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcDefaultIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcDefaultIntegrationTest.java index 9be3d1d2ca..fbb66e61c8 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcDefaultIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcDefaultIntegrationTest.java @@ -97,17 +97,17 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab @Test public void testServerMqttTwoWayRpc() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); } @Test public void testServerMqttTwoWayRpcOnShortTopic() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC); + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC); } @Test public void testServerMqttTwoWayRpcOnShortJsonTopic() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC); + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC); } @Test @@ -117,12 +117,12 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab @Test public void testGatewayServerMqttOneWayRpc() throws Exception { - processOneWayRpcTestGateway("Gateway Device OneWay RPC"); + processJsonOneWayRpcTestGateway("Gateway Device OneWay RPC"); } @Test public void testGatewayServerMqttTwoWayRpc() throws Exception { - processTwoWayRpcTestGateway("Gateway Device TwoWay RPC"); + processJsonTwoWayRpcTestGateway("Gateway Device TwoWay RPC"); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java index 1b468194b6..2d6a653264 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java @@ -17,8 +17,12 @@ package org.thingsboard.server.transport.mqtt.rpc; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.github.os72.protobuf.dynamic.DynamicSchema; +import com.google.protobuf.Descriptors; +import com.google.protobuf.DynamicMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.nimbusds.jose.util.StandardCharset; +import com.squareup.wire.schema.internal.parser.ProtoFileElement; import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -31,18 +35,23 @@ import org.junit.Assert; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.TransportPayloadType; +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; +import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** @@ -51,7 +60,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @Slf4j public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractMqttIntegrationTest { - protected static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}"; + protected static final String RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" + + "package rpc;\n" + + "\n" + + "message RpcRequestMsg {\n" + + " optional string method = 1;\n" + + " optional int32 requestId = 2;\n" + + " Params params = 3;\n" + + "\n" + + " message Params {\n" + + " optional string pin = 1;\n" + + " optional int32 value = 2;\n" + + " }\n" + + "}"; + + private static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}"; protected Long asyncContextTimeoutToUseRpcPlugin; @@ -64,7 +87,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM MqttAsyncClient client = getMqttAsyncClient(accessToken); CountDownLatch latch = new CountDownLatch(1); - TestMqttCallback callback = new TestMqttCallback(client, latch); + TestOneWayMqttCallback callback = new TestOneWayMqttCallback(client, latch); client.setCallback(callback); client.subscribe(rpcSubTopic, MqttQoS.AT_MOST_ONCE.value()); @@ -79,19 +102,19 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); } - protected void processOneWayRpcTestGateway(String deviceName) throws Exception { + protected void processJsonOneWayRpcTestGateway(String deviceName) throws Exception { MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); String payload = "{\"device\":\"" + deviceName + "\"}"; byte[] payloadBytes = payload.getBytes(); validateOneWayRpcGatewayResponse(deviceName, client, payloadBytes); } - protected void processTwoWayRpcTest(String rpcSubTopic) throws Exception { + protected void processJsonTwoWayRpcTest(String rpcSubTopic) throws Exception { MqttAsyncClient client = getMqttAsyncClient(accessToken); client.subscribe(rpcSubTopic, 1); CountDownLatch latch = new CountDownLatch(1); - TestMqttCallback callback = new TestMqttCallback(client, latch); + TestJsonMqttCallback callback = new TestJsonMqttCallback(client, latch); client.setCallback(callback); Thread.sleep(1000); @@ -105,6 +128,46 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM Assert.assertEquals(expected, result); } + protected void processProtoTwoWayRpcTest(String rpcSubTopic) throws Exception { + MqttAsyncClient client = getMqttAsyncClient(accessToken); + client.subscribe(rpcSubTopic, 1); + + CountDownLatch latch = new CountDownLatch(1); + TestProtoMqttCallback callback = new TestProtoMqttCallback(client, latch); + client.setCallback(callback); + + Thread.sleep(1000); + + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}"; + String deviceId = savedDevice.getId().getId().toString(); + + String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); + String expected = "{\"payload\":\"{\\\"value1\\\":\\\"A\\\",\\\"value2\\\":\\\"B\\\"}\"}"; + latch.await(3, TimeUnit.SECONDS); + Assert.assertEquals(expected, result); + } + + protected void processProtoTwoWayRpcTestGateway(String deviceName) throws Exception { + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); + TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); + byte[] payloadBytes = connectMsgProto.toByteArray(); + validateProtoTwoWayRpcGatewayResponse(deviceName, client, payloadBytes); + } + + protected void processProtoOneWayRpcTestGateway(String deviceName) throws Exception { + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); + TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); + byte[] payloadBytes = connectMsgProto.toByteArray(); + validateOneWayRpcGatewayResponse(deviceName, client, payloadBytes); + } + + private TransportApiProtos.ConnectMsg getConnectProto(String deviceName) { + TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder(); + builder.setDeviceName(deviceName); + builder.setDeviceType(TransportPayloadType.PROTOBUF.name()); + return builder.build(); + } + protected void processSequenceTwoWayRpcTest() throws Exception { List expected = new ArrayList<>(); List result = new ArrayList<>(); @@ -131,13 +194,13 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM Assert.assertEquals(expected, result); } - protected void processTwoWayRpcTestGateway(String deviceName) throws Exception { + protected void processJsonTwoWayRpcTestGateway(String deviceName) throws Exception { MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); String payload = "{\"device\":\"" + deviceName + "\"}"; byte[] payloadBytes = payload.getBytes(); - validateTwoWayRpcGateway(deviceName, client, payloadBytes); + validateJsonTwoWayRpcGatewayResponse(deviceName, client, payloadBytes); } protected void validateOneWayRpcGatewayResponse(String deviceName, MqttAsyncClient client, byte[] payloadBytes) throws Exception { @@ -151,7 +214,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM assertNotNull(savedDevice); CountDownLatch latch = new CountDownLatch(1); - TestMqttCallback callback = new TestMqttCallback(client, latch); + TestOneWayMqttCallback callback = new TestOneWayMqttCallback(client, latch); client.setCallback(callback); client.subscribe(MqttTopics.GATEWAY_RPC_TOPIC, MqttQoS.AT_MOST_ONCE.value()); @@ -166,7 +229,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); } - protected void validateTwoWayRpcGateway(String deviceName, MqttAsyncClient client, byte[] payloadBytes) throws Exception { + protected void validateJsonTwoWayRpcGatewayResponse(String deviceName, MqttAsyncClient client, byte[] payloadBytes) throws Exception { publishMqttMsg(client, payloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC); Device savedDevice = doExecuteWithRetriesAndInterval( @@ -177,7 +240,34 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM assertNotNull(savedDevice); CountDownLatch latch = new CountDownLatch(1); - TestMqttCallback callback = new TestMqttCallback(client, latch); + TestJsonMqttCallback callback = new TestJsonMqttCallback(client, latch); + client.setCallback(callback); + + client.subscribe(MqttTopics.GATEWAY_RPC_TOPIC, MqttQoS.AT_MOST_ONCE.value()); + + Thread.sleep(1000); + + String setGpioRequest = "{\"method\": \"toggle_gpio\", \"params\": {\"pin\":1}}"; + String deviceId = savedDevice.getId().getId().toString(); + String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); + latch.await(3, TimeUnit.SECONDS); + String expected = "{\"success\":true}"; + assertEquals(expected, result); + assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); + } + + protected void validateProtoTwoWayRpcGatewayResponse(String deviceName, MqttAsyncClient client, byte[] payloadBytes) throws Exception { + publishMqttMsg(client, payloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC); + + Device savedDevice = doExecuteWithRetriesAndInterval( + () -> getDeviceByName(deviceName), + 20, + 100 + ); + assertNotNull(savedDevice); + + CountDownLatch latch = new CountDownLatch(1); + TestProtoMqttCallback callback = new TestProtoMqttCallback(client, latch); client.setCallback(callback); client.subscribe(MqttTopics.GATEWAY_RPC_TOPIC, MqttQoS.AT_MOST_ONCE.value()); @@ -197,7 +287,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM return doGet("/api/tenant/devices?deviceName=" + deviceName, Device.class); } - protected MqttMessage processMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException { + protected MqttMessage processJsonMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException { MqttMessage message = new MqttMessage(); if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC) || requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC_V2)) { message.setPayload(DEVICE_RESPONSE.getBytes(StandardCharset.UTF_8)); @@ -210,13 +300,45 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM return message; } - protected class TestMqttCallback implements MqttCallback { + protected class TestOneWayMqttCallback implements MqttCallback { + + private final MqttAsyncClient client; + private final CountDownLatch latch; + private Integer qoS; + + TestOneWayMqttCallback(MqttAsyncClient client, CountDownLatch latch) { + this.client = client; + this.latch = latch; + } + + int getQoS() { + return qoS; + } + + @Override + public void connectionLost(Throwable throwable) { + } + + @Override + public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception { + log.info("Message Arrived: " + Arrays.toString(mqttMessage.getPayload())); + qoS = mqttMessage.getQos(); + latch.countDown(); + } + + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + + } + } + + protected class TestJsonMqttCallback implements MqttCallback { private final MqttAsyncClient client; private final CountDownLatch latch; private Integer qoS; - TestMqttCallback(MqttAsyncClient client, CountDownLatch latch) { + TestJsonMqttCallback(MqttAsyncClient client, CountDownLatch latch) { this.client = client; this.latch = latch; } @@ -239,7 +361,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM responseTopic = requestTopic.replace("request", "response"); } qoS = mqttMessage.getQos(); - client.publish(responseTopic, processMessageArrived(requestTopic, mqttMessage)); + client.publish(responseTopic, processJsonMessageArrived(requestTopic, mqttMessage)); latch.countDown(); } @@ -249,6 +371,98 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM } } + protected class TestProtoMqttCallback implements MqttCallback { + + private final MqttAsyncClient client; + private final CountDownLatch latch; + private Integer qoS; + + TestProtoMqttCallback(MqttAsyncClient client, CountDownLatch latch) { + this.client = client; + this.latch = latch; + } + + int getQoS() { + return qoS; + } + + @Override + public void connectionLost(Throwable throwable) { + } + + @Override + public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception { + log.info("Message Arrived: " + Arrays.toString(mqttMessage.getPayload())); + String responseTopic; + if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC_V2)) { + responseTopic = requestTopic.replace("req", "res"); + } else { + responseTopic = requestTopic.replace("request", "response"); + } + qoS = mqttMessage.getQos(); + client.publish(responseTopic, processProtoMessageArrived(requestTopic, mqttMessage)); + latch.countDown(); + } + + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + + } + } + + protected MqttMessage processProtoMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException { + MqttMessage message = new MqttMessage(); + if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC) || requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC_V2)) { + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = getProtoTransportPayloadConfiguration(); + ProtoFileElement rpcRequestProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(RPC_REQUEST_PROTO_SCHEMA); + DynamicSchema rpcRequestProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(rpcRequestProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_REQUEST_PROTO_SCHEMA); + + byte[] requestPayload = mqttMessage.getPayload(); + DynamicMessage.Builder rpcRequestMsg = rpcRequestProtoSchema.newMessageBuilder("RpcRequestMsg"); + Descriptors.Descriptor rpcRequestMsgDescriptor = rpcRequestMsg.getDescriptorForType(); + assertNotNull(rpcRequestMsgDescriptor); + try { + DynamicMessage dynamicMessage = DynamicMessage.parseFrom(rpcRequestMsgDescriptor, requestPayload); + List fields = rpcRequestMsgDescriptor.getFields(); + for (Descriptors.FieldDescriptor fieldDescriptor: fields) { + assertTrue(dynamicMessage.hasField(fieldDescriptor)); + } + ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_RPC_RESPONSE_PROTO_SCHEMA); + DynamicSchema rpcResponseProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_RESPONSE_PROTO_SCHEMA); + + DynamicMessage.Builder rpcResponseBuilder = rpcResponseProtoSchema.newMessageBuilder("RpcResponseMsg"); + Descriptors.Descriptor rpcResponseMsgDescriptor = rpcResponseBuilder.getDescriptorForType(); + assertNotNull(rpcResponseMsgDescriptor); + DynamicMessage rpcResponseMsg = rpcResponseBuilder + .setField(rpcResponseMsgDescriptor.findFieldByName("payload"), DEVICE_RESPONSE) + .build(); + message.setPayload(rpcResponseMsg.toByteArray()); + } catch (InvalidProtocolBufferException e) { + log.warn("Command Response Ack Error, Invalid response received: ", e); + } + } else { + TransportApiProtos.GatewayDeviceRpcRequestMsg msg = TransportApiProtos.GatewayDeviceRpcRequestMsg.parseFrom(mqttMessage.getPayload()); + String deviceName = msg.getDeviceName(); + int requestId = msg.getRpcRequestMsg().getRequestId(); + TransportApiProtos.GatewayRpcResponseMsg gatewayRpcResponseMsg = TransportApiProtos.GatewayRpcResponseMsg.newBuilder() + .setDeviceName(deviceName) + .setId(requestId) + .setData("{\"success\": true}") + .build(); + message.setPayload(gatewayRpcResponseMsg.toByteArray()); + } + return message; + } + + private ProtoTransportPayloadConfiguration getProtoTransportPayloadConfiguration() { + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); + return (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; + } + protected class TestSequenceMqttCallback implements MqttCallback { private final MqttAsyncClient client; @@ -273,7 +487,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM var qoS = mqttMessage.getQos(); client.messageArrivedComplete(mqttMessage.getId(), qoS); - client.publish(responseTopic, processMessageArrived(requestTopic, mqttMessage)); + client.publish(responseTopic, processJsonMessageArrived(requestTopic, mqttMessage)); latch.countDown(); } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcJsonIntegrationTest.java index f8c0cd8bed..14098c6e2a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcJsonIntegrationTest.java @@ -53,30 +53,30 @@ public abstract class AbstractMqttServerSideRpcJsonIntegrationTest extends Abstr @Test public void testServerMqttTwoWayRpc() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); } @Test public void testServerMqttTwoWayRpcOnShortTopic() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC); + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC); } @Test public void testServerMqttTwoWayRpcOnShortJsonTopic() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC); + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC); } @Test public void testGatewayServerMqttOneWayRpc() throws Exception { - processOneWayRpcTestGateway("Gateway Device OneWay RPC Json"); + processJsonOneWayRpcTestGateway("Gateway Device OneWay RPC Json"); } @Test public void testGatewayServerMqttTwoWayRpc() throws Exception { - processTwoWayRpcTestGateway("Gateway Device TwoWay RPC Json"); + processJsonTwoWayRpcTestGateway("Gateway Device TwoWay RPC Json"); } - protected void processOneWayRpcTestGateway(String deviceName) throws Exception { + protected void processJsonOneWayRpcTestGateway(String deviceName) throws Exception { MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); String payload = "{\"device\": \"" + deviceName + "\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}"; byte[] payloadBytes = payload.getBytes(); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcProtoIntegrationTest.java index 2c9f1f7889..30227dfe3b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcProtoIntegrationTest.java @@ -15,60 +15,20 @@ */ package org.thingsboard.server.transport.mqtt.rpc; -import com.github.os72.protobuf.dynamic.DynamicSchema; -import com.google.protobuf.Descriptors; -import com.google.protobuf.DynamicMessage; -import com.google.protobuf.InvalidProtocolBufferException; -import com.squareup.wire.schema.internal.parser.ProtoFileElement; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.core.CoapHandler; -import org.eclipse.californium.core.CoapResponse; -import org.eclipse.californium.core.coap.MediaTypeRegistry; -import org.eclipse.paho.client.mqttv3.MqttAsyncClient; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.eclipse.paho.client.mqttv3.MqttMessage; -import org.jetbrains.annotations.NotNull; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.TransportPayloadType; -import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.MqttTopics; -import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; -import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; -import org.thingsboard.server.gen.transport.TransportApiProtos; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @Slf4j public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest { - private static final String RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" + - "package rpc;\n" + - "\n" + - "message RpcRequestMsg {\n" + - " optional string method = 1;\n" + - " optional int32 requestId = 2;\n" + - " Params params = 3;\n" + - "\n" + - " message Params {\n" + - " optional string pin = 1;\n" + - " optional int32 value = 2;\n" + - " }\n" + - "}"; - @Before public void beforeTest() throws Exception { - processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED); + processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, false, false); } @After @@ -93,122 +53,27 @@ public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends Abst @Test public void testServerMqttTwoWayRpc() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC); } @Test public void testServerMqttTwoWayRpcOnShortTopic() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC); + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC); } @Test public void testServerMqttTwoWayRpcOnShortProtoTopic() throws Exception { - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC); + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC); } @Test public void testGatewayServerMqttOneWayRpc() throws Exception { - processOneWayRpcTestGateway("Gateway Device OneWay RPC Proto"); + processProtoOneWayRpcTestGateway("Gateway Device OneWay RPC Proto"); } @Test public void testGatewayServerMqttTwoWayRpc() throws Exception { - processTwoWayRpcTestGateway("Gateway Device TwoWay RPC Proto"); - } - - protected void processTwoWayRpcTestGateway(String deviceName) throws Exception { - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); - TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); - byte[] payloadBytes = connectMsgProto.toByteArray(); - validateTwoWayRpcGateway(deviceName, client, payloadBytes); - } - - protected void processOneWayRpcTestGateway(String deviceName) throws Exception { - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); - TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); - byte[] payloadBytes = connectMsgProto.toByteArray(); - validateOneWayRpcGatewayResponse(deviceName, client, payloadBytes); - } - - - private TransportApiProtos.ConnectMsg getConnectProto(String deviceName) { - TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder(); - builder.setDeviceName(deviceName); - builder.setDeviceType(TransportPayloadType.PROTOBUF.name()); - return builder.build(); + processProtoTwoWayRpcTestGateway("Gateway Device TwoWay RPC Proto"); } - protected void processTwoWayRpcTest(String rpcSubTopic) throws Exception { - MqttAsyncClient client = getMqttAsyncClient(accessToken); - client.subscribe(rpcSubTopic, 1); - - CountDownLatch latch = new CountDownLatch(1); - TestMqttCallback callback = new TestMqttCallback(client, latch); - client.setCallback(callback); - - Thread.sleep(1000); - - String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}"; - String deviceId = savedDevice.getId().getId().toString(); - - String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); - String expected = "{\"payload\":\"{\\\"value1\\\":\\\"A\\\",\\\"value2\\\":\\\"B\\\"}\"}"; - latch.await(3, TimeUnit.SECONDS); - Assert.assertEquals(expected, result); - } - - protected MqttMessage processMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException { - MqttMessage message = new MqttMessage(); - if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC) || requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC_V2)) { - ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = getProtoTransportPayloadConfiguration(); - ProtoFileElement rpcRequestProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(RPC_REQUEST_PROTO_SCHEMA); - DynamicSchema rpcRequestProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(rpcRequestProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_REQUEST_PROTO_SCHEMA); - - byte[] requestPayload = mqttMessage.getPayload(); - DynamicMessage.Builder rpcRequestMsg = rpcRequestProtoSchema.newMessageBuilder("RpcRequestMsg"); - Descriptors.Descriptor rpcRequestMsgDescriptor = rpcRequestMsg.getDescriptorForType(); - assertNotNull(rpcRequestMsgDescriptor); - try { - DynamicMessage dynamicMessage = DynamicMessage.parseFrom(rpcRequestMsgDescriptor, requestPayload); - List fields = rpcRequestMsgDescriptor.getFields(); - for (Descriptors.FieldDescriptor fieldDescriptor: fields) { - assertTrue(dynamicMessage.hasField(fieldDescriptor)); - } - ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_RPC_RESPONSE_PROTO_SCHEMA); - DynamicSchema rpcResponseProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_RESPONSE_PROTO_SCHEMA); - - DynamicMessage.Builder rpcResponseBuilder = rpcResponseProtoSchema.newMessageBuilder("RpcResponseMsg"); - Descriptors.Descriptor rpcResponseMsgDescriptor = rpcResponseBuilder.getDescriptorForType(); - assertNotNull(rpcResponseMsgDescriptor); - DynamicMessage rpcResponseMsg = rpcResponseBuilder - .setField(rpcResponseMsgDescriptor.findFieldByName("payload"), DEVICE_RESPONSE) - .build(); - message.setPayload(rpcResponseMsg.toByteArray()); - } catch (InvalidProtocolBufferException e) { - log.warn("Command Response Ack Error, Invalid response received: ", e); - } - } else { - TransportApiProtos.GatewayDeviceRpcRequestMsg msg = TransportApiProtos.GatewayDeviceRpcRequestMsg.parseFrom(mqttMessage.getPayload()); - String deviceName = msg.getDeviceName(); - int requestId = msg.getRpcRequestMsg().getRequestId(); - TransportApiProtos.GatewayRpcResponseMsg gatewayRpcResponseMsg = TransportApiProtos.GatewayRpcResponseMsg.newBuilder() - .setDeviceName(deviceName) - .setId(requestId) - .setData("{\"success\": true}") - .build(); - message.setPayload(gatewayRpcResponseMsg.toByteArray()); - } - return message; - } - - private ProtoTransportPayloadConfiguration getProtoTransportPayloadConfiguration() { - DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); - assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); - MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; - TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); - assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); - return (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; - } - - } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java new file mode 100644 index 0000000000..559ae945d1 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java @@ -0,0 +1,24 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.rpc.sql; + +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest; + + +@DaoSqlTest +public class MqttServerSideRpcBackwardCompatibilityIntegrationTest extends AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest { +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcIntegrationTest.java similarity index 89% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcIntegrationTest.java index 816ac7780d..b0438ca96b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcIntegrationTest.java @@ -22,5 +22,5 @@ import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcDefaul * Created by Valerii Sosliuk on 8/22/2017. */ @DaoSqlTest -public class MqttServerSideRpcSqlIntegrationTest extends AbstractMqttServerSideRpcDefaultIntegrationTest { +public class MqttServerSideRpcIntegrationTest extends AbstractMqttServerSideRpcDefaultIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonIntegrationTest.java similarity index 88% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonIntegrationTest.java index c17570b5ca..22eeea1624 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcJsonIntegrationTest; @DaoSqlTest -public class MqttServerSideRpcJsonSqlIntegrationTest extends AbstractMqttServerSideRpcJsonIntegrationTest { +public class MqttServerSideRpcJsonIntegrationTest extends AbstractMqttServerSideRpcJsonIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoIntegrationTest.java similarity index 88% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoIntegrationTest.java index fa21510bb1..0daf14b7c3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoIntegrationTest.java @@ -20,5 +20,5 @@ import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcProtoI @DaoSqlTest -public class MqttServerSideRpcProtoSqlIntegrationTest extends AbstractMqttServerSideRpcProtoIntegrationTest { +public class MqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcProtoIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java index afe624c55b..a68ece0df0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java @@ -54,6 +54,12 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postAttributesMsg.toByteArray(), false); } + @Test + public void testPushAttributesWithEnabledJsonBackwardCompatibility() throws Exception { + super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC, true, false); + processJsonPayloadAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), PAYLOAD_VALUES_STR.getBytes()); + } + @Test public void testPushAttributesWithExplicitPresenceProtoKeys() throws Exception { super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesIntegrationTest.java similarity index 90% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesIntegrationTest.java index c3dafc4eef..06f222f8a1 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest; @DaoSqlTest -public class MqttAttributesSqlIntegrationTest extends AbstractMqttAttributesIntegrationTest { +public class MqttAttributesIntegrationTest extends AbstractMqttAttributesIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesJsonIntegrationTest.java similarity index 89% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesJsonIntegrationTest.java index 306b89ad23..eefde6336c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesJsonIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest; @DaoSqlTest -public class MqttAttributesSqlJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest { +public class MqttAttributesJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesProtoIntegrationTest.java similarity index 89% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesProtoIntegrationTest.java index 57376961db..a976f54e35 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesProtoIntegrationTest.java @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest; @DaoSqlTest -public class MqttAttributesSqlProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest { +public class MqttAttributesProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java index a10e19a35c..fd6cf9b9ae 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java @@ -21,9 +21,7 @@ import com.google.protobuf.DynamicMessage; import com.squareup.wire.schema.internal.parser.ProtoFileElement; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; -import org.jetbrains.annotations.NotNull; import org.junit.After; -import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @@ -37,7 +35,6 @@ import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportProtos; import java.util.Arrays; -import java.util.Collections; import java.util.List; import static org.junit.Assert.assertNotNull; @@ -60,6 +57,12 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postTelemetryMsg.toByteArray(), false, false); } + @Test + public void testPushTelemetryWithEnabledJsonBackwardCompatibility() throws Exception { + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, true, false); + processJsonPayloadTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), PAYLOAD_VALUES_STR.getBytes(), false); + } + @Test public void testPushTelemetryWithTs() throws Exception { String schemaStr = "syntax =\"proto3\";\n" + @@ -87,7 +90,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac " }\n" + " }\n" + "}"; - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); DynamicSchema telemetrySchema = getDynamicSchema(schemaStr); DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); @@ -189,7 +192,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac " }\n" + " }\n" + "}"; - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); DynamicSchema telemetrySchema = getDynamicSchema(schemaStr); DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); @@ -249,7 +252,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @Test public void testPushTelemetryGateway() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder(); List expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); String deviceName1 = "Device A"; @@ -263,7 +266,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @Test public void testGatewayConnect() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); String deviceName = "Device A"; TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); From c1823ff1e2b7ecc72faeefb49d300f0a3fcaf430 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 28 Oct 2021 13:41:37 +0300 Subject: [PATCH 168/303] UI: Refactoring widget settings --- .../widget/legend-config.component.html | 6 +- .../widget/legend-config.component.ts | 78 ++- .../widget/widget-config.component.html | 458 +++++++++--------- .../widget/widget-config.component.scss | 7 +- 4 files changed, 269 insertions(+), 280 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html index 46faecb9f5..7d824a0186 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html @@ -38,9 +38,6 @@
    - - {{ 'legend.sort-legend' | translate }} - {{ 'legend.show-min' | translate }} @@ -53,5 +50,8 @@ {{ 'legend.show-total' | translate }} + + {{ 'legend.sort-legend' | translate }} +
    diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts index eb38e0adb1..1fa5e166f4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts @@ -14,14 +14,7 @@ /// limitations under the License. /// -import { - Component, - forwardRef, - Input, - OnDestroy, - OnInit, - ViewContainerRef -} from '@angular/core'; +import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; import { isDefined } from '@core/utils'; import { @@ -32,6 +25,7 @@ import { legendPositionTranslationMap } from '@shared/models/widget.models'; import { Subscription } from 'rxjs'; + // @dynamic @Component({ selector: 'tb-legend-config', @@ -49,7 +43,6 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc @Input() disabled: boolean; - legendSettings: LegendConfig; legendConfigForm: FormGroup; legendDirection = LegendDirection; legendDirections = Object.keys(LegendDirection); @@ -58,12 +51,11 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc legendPositions = Object.keys(LegendPosition); legendPositionTranslations = legendPositionTranslationMap; - legendSettingsChangesSubscription: Subscription; - + private legendSettingsFormChanges$: Subscription; + private legendSettingsFormDirectionChanges$: Subscription; private propagateChange = (_: any) => {}; - constructor(public fb: FormBuilder, - public viewContainerRef: ViewContainerRef) { + constructor(private fb: FormBuilder) { } ngOnInit(): void { @@ -76,9 +68,13 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc showAvg: [null, []], showTotal: [null, []] }); - this.legendConfigForm.get('direction').valueChanges.subscribe((direction: LegendDirection) => { - this.onDirectionChanged(direction); - }); + this.legendSettingsFormDirectionChanges$ = this.legendConfigForm.get('direction').valueChanges + .subscribe((direction: LegendDirection) => { + this.onDirectionChanged(direction); + }); + this.legendSettingsFormChanges$ = this.legendConfigForm.valueChanges.subscribe( + () => this.legendConfigUpdated() + ); } private onDirectionChanged(direction: LegendDirection) { @@ -93,7 +89,14 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc } ngOnDestroy(): void { - this.removeChangeSubscriptions(); + if (this.legendSettingsFormDirectionChanges$) { + this.legendSettingsFormDirectionChanges$.unsubscribe(); + this.legendSettingsFormDirectionChanges$ = null; + } + if (this.legendSettingsFormChanges$) { + this.legendSettingsFormChanges$.unsubscribe(); + this.legendSettingsFormChanges$ = null; + } } registerOnChange(fn: any): void { @@ -112,39 +115,22 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc } } - private removeChangeSubscriptions() { - if (this.legendSettingsChangesSubscription) { - this.legendSettingsChangesSubscription.unsubscribe(); - this.legendSettingsChangesSubscription = null; - } - } - - private createChangeSubscriptions() { - this.legendSettingsChangesSubscription = this.legendConfigForm.valueChanges.subscribe( - () => this.legendConfigUpdated() - ); - } - - writeValue(obj: LegendConfig): void { - this.legendSettings = obj; - this.removeChangeSubscriptions(); - if (this.legendSettings) { + writeValue(legendConfig: LegendConfig): void { + if (legendConfig) { this.legendConfigForm.patchValue({ - direction: this.legendSettings.direction, - position: this.legendSettings.position, - sortDataKeys: isDefined(this.legendSettings.sortDataKeys) ? this.legendSettings.sortDataKeys : false, - showMin: isDefined(this.legendSettings.showMin) ? this.legendSettings.showMin : false, - showMax: isDefined(this.legendSettings.showMax) ? this.legendSettings.showMax : false, - showAvg: isDefined(this.legendSettings.showAvg) ? this.legendSettings.showAvg : false, - showTotal: isDefined(this.legendSettings.showTotal) ? this.legendSettings.showTotal : false - }); + direction: legendConfig.direction, + position: legendConfig.position, + sortDataKeys: isDefined(legendConfig.sortDataKeys) ? legendConfig.sortDataKeys : false, + showMin: isDefined(legendConfig.showMin) ? legendConfig.showMin : false, + showMax: isDefined(legendConfig.showMax) ? legendConfig.showMax : false, + showAvg: isDefined(legendConfig.showAvg) ? legendConfig.showAvg : false, + showTotal: isDefined(legendConfig.showTotal) ? legendConfig.showTotal : false + }, {emitEvent: false}); } - this.onDirectionChanged(this.legendSettings.direction); - this.createChangeSubscriptions(); + this.onDirectionChanged(legendConfig.direction); } private legendConfigUpdated() { - this.legendSettings = this.legendConfigForm.value; - this.propagateChange(this.legendSettings); + this.propagateChange(this.legendConfigForm.value); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 0121b07cf6..555e489afa 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -82,241 +82,241 @@
    - - - -
    widget-config.datasources
    -
    {{ 'widget-config.maximum-datasources' | translate:{count: modelValue?.typeParameters.maxDatasources} }}
    -
    -
    -
    - datasource.add-datasource-prompt -
    - -
    - -
    - widget-config.datasource-type - widget-config.datasource-parameters - -
    + + + + +
    widget-config.datasources
    +
    {{ 'widget-config.maximum-datasources' | translate:{count: modelValue?.typeParameters.maxDatasources} }}
    +
    +
    +
    + datasource.add-datasource-prompt
    -
    - - - - -
    -
    - - {{$index + 1}}. -
    -
    -
    - - - - {{ datasourceTypesTranslations.get(datasourceType) | translate }} - - - -
    - - - - - - - - - - - - - - - - + +
    + +
    + widget-config.datasource-type + widget-config.datasource-parameters + +
    +
    +
    + + + + +
    +
    + + {{$index + 1}}. +
    +
    +
    + + + + {{ datasourceTypesTranslations.get(datasourceType) | translate }} + + + +
    + + + + + + + + + + + + + + + + +
    + +
    - - -
    - + +
    -
    - - + + +
    +
    +
    +
    - -
    - -
    -
    - - - - {{ 'widget-config.target-device' | translate }} - - -
    - - -
    -
    - - - - {{ 'widget-config.alarm-source' | translate }} - - -
    -
    - - - - {{ datasourceTypesTranslations.get(datasourceType) | translate }} - - - -
    - - - - - - + + + + + {{ 'widget-config.target-device' | translate }} + + +
    + + +
    +
    + + + + {{ 'widget-config.alarm-source' | translate }} + + +
    +
    + + + + {{ datasourceTypesTranslations.get(datasourceType) | translate }} + + + +
    + + + + + + +
    + +
    - - -
    -
    -
    - -
    - - - widget-config.data-settings - - -
    - - widget-config.units - - - - widget-config.decimals - -
    -
    -
    + + + + widget-config.data-settings + + +
    + + widget-config.units + + + + widget-config.decimals + + +
    +
    +
    +
    -
    +
    widget-config.title - + {{ 'widget-config.display-title' | translate }}
    -
    +
    widget-config.title-icon {{ 'widget-config.display-icon' | translate }} @@ -368,10 +368,10 @@
    -
    +
    widget-config.widget-style
    + fxFlex="100%" fxLayoutGap="8px" class="tb-widget-style">
    - + {{ 'widget-config.drop-shadow' | translate }} @@ -421,7 +421,7 @@
    -
    +
    widget-config.legend @@ -439,7 +439,7 @@
    -
    +
    widget-config.mobile-mode-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss index 4c4fa317ce..8d8cd742c6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss @@ -85,6 +85,9 @@ padding: 0 16px 8px; } } + .tb-widget-style { + margin-top: 16px; + } } } @@ -128,10 +131,10 @@ align-items: center; } .mat-expansion-panel-body{ - padding: 0 0 16px; + padding: 0; } .tb-json-object-panel { - margin: 0; + margin: 0 0 8px; } .mat-checkbox-layout { margin: 5px 0; From ec05751198460f715a540e413361ac3edb95b6d0 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 28 Oct 2021 13:48:07 +0300 Subject: [PATCH 169/303] fix typo in AbstractMqttAttributesUpdatesJsonIntegrationTest --- ...ractMqttAttributesUpdatesJsonIntegrationTest.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java index 7a8b28356c..02dbe8e8a8 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java @@ -20,9 +20,11 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; @Slf4j -public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { +public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesIntegrationTest { @Before public void beforeTest() throws Exception { @@ -36,21 +38,21 @@ public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends A @Test public void testJsonSubscribeToAttributesUpdatesFromTheServer() throws Exception { - super.testJsonSubscribeToAttributesUpdatesFromTheServer(); + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); } @Test public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception { - super.testJsonSubscribeToAttributesUpdatesFromTheServerOnShortTopic(); + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC); } @Test public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception { - super.testJsonSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic(); + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC); } @Test public void testJsonSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { - super.testJsonSubscribeToAttributesUpdatesFromTheServerGateway(); + processJsonGatewayTestSubscribeToAttributesUpdates(); } } From fbdb1c223fcfb998e375d2eeccef7a995eb8fa90 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 28 Oct 2021 15:12:55 +0300 Subject: [PATCH 170/303] UI: Fixed display toast in fullscreen dashboard mode --- .../components/dashboard-page/dashboard-page.component.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index b17f597c6d..bceee03a41 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
    Date: Fri, 22 Oct 2021 18:23:07 +0300 Subject: [PATCH 172/303] Validate tenant profile usage - can not use isolated profiles in monolith setup --- .../server/dao/tenant/TenantServiceImpl.java | 13 +++++++++++ .../dao/service/BaseTenantServiceTest.java | 22 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index eab0a070f5..7314f54b39 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; @@ -55,6 +56,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe private static final String DEFAULT_TENANT_REGION = "Global"; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; + @Value("${zk.enabled}") + private Boolean zkEnabled; + @Autowired private TenantDao tenantDao; @@ -190,6 +194,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe if (!StringUtils.isEmpty(tenant.getEmail())) { validateEmail(tenant.getEmail()); } + validateTenantProfile(tenantId, tenant); } @Override @@ -198,6 +203,14 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe if (old == null) { throw new DataValidationException("Can't update non existing tenant!"); } + validateTenantProfile(tenantId, tenant); + } + + private void validateTenantProfile(TenantId tenantId, Tenant tenant) { + TenantProfile tenantProfileById = tenantProfileService.findTenantProfileById(tenantId, tenant.getTenantProfileId()); + if (!zkEnabled && (tenantProfileById.isIsolatedTbCore() || tenantProfileById.isIsolatedTbRuleEngine())) { + throw new DataValidationException("Can't use isolated tenant profiles in monolith setup!"); + } } }; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 5930f7ae4d..29b0558c71 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -20,8 +20,12 @@ import org.junit.Assert; import org.junit.Test; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.dao.exception.DataValidationException; import java.util.ArrayList; @@ -253,4 +257,22 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Assert.assertTrue(pageData.getData().isEmpty()); } + + @Test(expected = DataValidationException.class) + public void testSaveTenantWithIsolatedProfileInMonolithSetup() { + TenantProfile tenantProfile = new TenantProfile(); + tenantProfile.setName("Isolated Tenant Profile"); + TenantProfileData profileData = new TenantProfileData(); + profileData.setConfiguration(new DefaultTenantProfileConfiguration()); + tenantProfile.setProfileData(profileData); + tenantProfile.setDefault(false); + tenantProfile.setIsolatedTbCore(true); + tenantProfile.setIsolatedTbRuleEngine(true); + TenantProfile isolatedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); + + Tenant tenant = new Tenant(); + tenant.setTitle("Tenant"); + tenant.setTenantProfileId(isolatedTenantProfile.getId()); + tenantService.saveTenant(tenant); + } } From 0635929b19f2cb0c9001cb66e8f5d4b90585b131 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 29 Oct 2021 10:18:50 +0300 Subject: [PATCH 173/303] Edge Swagger docs - part 2 --- .../controller/ControllerConstants.java | 1 + .../controller/DashboardController.java | 21 ++++-- .../server/controller/EdgeController.java | 16 ++-- .../controller/RuleChainController.java | 34 +++++++-- .../server/common/data/edge/Edge.java | 74 ++++++++++++++++++- .../common/data/edge/EdgeSearchQuery.java | 4 + .../assets/locale/locale.constant-de_DE.json | 2 +- 7 files changed, 133 insertions(+), 19 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index 7c881e8b67..97c2854b89 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -23,6 +23,7 @@ public class ControllerConstants { protected static final String CUSTOMER_ID = "customerId"; protected static final String TENANT_ID = "tenantId"; protected static final String DEVICE_ID = "deviceId"; + protected static final String EDGE_ID = "edgeId"; protected static final String RPC_ID = "rpcId"; protected static final String ENTITY_ID = "entityId"; protected static final String PAGE_DATA_PARAMETERS = "You can specify parameters to filter the results. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 8b3647efe2..9035e74d54 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -51,7 +51,6 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; @@ -69,6 +68,8 @@ import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_SO import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_TEXT_SEARCH_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; @@ -906,24 +907,32 @@ public class DashboardController extends BaseController { } } + @ApiOperation(value = "Get Edge Dashboards (getEdgeDashboards)", + notes = "Returns a page of dashboard info objects assigned to the specified edge. " + + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/{edgeId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getEdgeDashboards( - @PathVariable("edgeId") String strEdgeId, + @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(EDGE_ID) String strEdgeId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = DASHBOARD_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder, - @RequestParam(required = false) Long startTime, - @RequestParam(required = false) Long endTime) throws ThingsboardException { + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("edgeId", strEdgeId); try { TenantId tenantId = getCurrentUser().getTenantId(); EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); checkEdgeId(edgeId, Operation.READ); - TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); PageData nonFilteredResult = dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); List filteredDashboards = nonFilteredResult.getData().stream().filter(dashboardInfo -> { try { diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 219041e82c..4b57c8128d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -452,17 +452,17 @@ public class EdgeController extends BaseController { } } - @ApiOperation(value = "Set root rule chain for provided edge (setRootRuleChain)", + @ApiOperation(value = "Set root rule chain for provided edge (setEdgeRootRuleChain)", notes = "Change root rule chain of the edge to the new provided rule chain. \n" + "This operation will send a notification to update root rule chain on remote edge service." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST) @ResponseBody - public Edge setRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) - @PathVariable(EDGE_ID) String strEdgeId, - @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true) - @PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException { + public Edge setEdgeRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(EDGE_ID) String strEdgeId, + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true) + @PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException { checkParameter(EDGE_ID, strEdgeId); checkParameter("ruleChainId", strRuleChainId); try { @@ -736,6 +736,9 @@ public class EdgeController extends BaseController { edge.setEdgeLicenseKey(null); } + @ApiOperation(value = "Check edge license (checkInstance)", + notes = "Checks license request from edge service by forwarding request to license portal.", + produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/license/checkInstance", method = RequestMethod.POST) @ResponseBody public ResponseEntity checkInstance(@RequestBody JsonNode request) throws ThingsboardException { @@ -748,6 +751,9 @@ public class EdgeController extends BaseController { } } + @ApiOperation(value = "Activate edge instance (activateInstance)", + notes = "Activates edge license on license portal.", + produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/license/activateInstance", params = {"licenseSecret", "releaseDate"}, method = RequestMethod.POST) @ResponseBody public ResponseEntity activateInstance(@RequestParam String licenseSecret, diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 8996367c36..5f12e3732c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -83,6 +83,8 @@ import java.util.stream.Collectors; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID; +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; @@ -676,17 +678,25 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Get Edge Rule Chains (getEdgeRuleChains)", + notes = "Returns a page of Rule Chains assigned to the specified edge. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getEdgeRuleChains( - @PathVariable("edgeId") String strEdgeId, + @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(EDGE_ID) String strEdgeId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = RULE_CHAIN_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { - checkParameter("edgeId", strEdgeId); + checkParameter(EDGE_ID, strEdgeId); try { TenantId tenantId = getCurrentUser().getTenantId(); EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); @@ -698,10 +708,14 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Set Edge Template Root Rule Chain (setEdgeTemplateRootRuleChain)", + notes = "Makes the rule chain to be root rule chain for any new edge that will be created. " + + "Does not update root rule chain for already created edges. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/{ruleChainId}/edgeTemplateRoot", method = RequestMethod.POST) @ResponseBody - public RuleChain setEdgeTemplateRootRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + public RuleChain setEdgeTemplateRootRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { checkParameter(RULE_CHAIN_ID, strRuleChainId); try { RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); @@ -717,10 +731,14 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Set Auto Assign To Edge Rule Chain (setAutoAssignToEdgeRuleChain)", + notes = "Makes the rule chain to be automatically assigned for any new edge that will be created. " + + "Does not assign this rule chain for already created edges. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/{ruleChainId}/autoAssignToEdge", method = RequestMethod.POST) @ResponseBody - public RuleChain setAutoAssignToEdgeRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + public RuleChain setAutoAssignToEdgeRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { checkParameter(RULE_CHAIN_ID, strRuleChainId); try { RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); @@ -736,10 +754,14 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Unset Auto Assign To Edge Rule Chain (unsetAutoAssignToEdgeRuleChain)", + notes = "Removes the rule chain from the list of rule chains that are going to be automatically assigned for any new edge that will be created. " + + "Does not unassign this rule chain for already assigned edges. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/{ruleChainId}/autoAssignToEdge", method = RequestMethod.DELETE) @ResponseBody - public RuleChain unsetAutoAssignToEdgeRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + public RuleChain unsetAutoAssignToEdgeRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { checkParameter(RULE_CHAIN_ID, strRuleChainId); try { RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); @@ -756,6 +778,8 @@ public class RuleChainController extends BaseController { } // TODO: @voba refactor this - add new config to edge rule chain to set it as auto-assign + @ApiOperation(value = "Get Auto Assign To Edge Rule Chains (getAutoAssignToEdgeRuleChains)", + notes = "Returns a list of Rule Chains that will be assigned to a newly created edge. " + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/ruleChain/autoAssignToEdgeRuleChains", method = RequestMethod.GET) @ResponseBody diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java index 7a858f8325..785e5e9bb0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java @@ -15,8 +15,9 @@ */ package org.thingsboard.server.common.data.edge; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.EqualsAndHashCode; -import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.thingsboard.server.common.data.HasCustomerId; @@ -28,9 +29,9 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +@ApiModel @EqualsAndHashCode(callSuper = true) @ToString -@Getter @Setter public class Edge extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasCustomerId { @@ -82,8 +83,77 @@ public class Edge extends SearchTextBasedWithAdditionalInfo implements H this.cloudEndpoint = edge.getCloudEndpoint(); } + @ApiModelProperty(position = 1, value = "JSON object with the Edge Id. " + + "Specify this field to update the Edge. " + + "Referencing non-existing Edge Id will cause error. " + + "Omit this field to create new Edge." ) + @Override + public EdgeId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the edge creation, in milliseconds", example = "1609459200000", readOnly = true) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Use 'assignDeviceToTenant' to change the Tenant Id.", readOnly = true) + @Override + public TenantId getTenantId() { + return this.tenantId; + } + + @ApiModelProperty(position = 4, value = "JSON object with Customer Id. Use 'assignEdgeToCustomer' to change the Customer Id.", readOnly = true) + @Override + public CustomerId getCustomerId() { + return this.customerId; + } + + @ApiModelProperty(position = 5, value = "JSON object with Root Rule Chain Id. Use 'setEdgeRootRuleChain' to change the Root Rule Chain Id.", readOnly = true) + public RuleChainId getRootRuleChainId() { + return this.rootRuleChainId; + } + + @ApiModelProperty(position = 6, required = true, value = "Unique Edge Name in scope of Tenant", example = "Silo_A_Edge") + @Override + public String getName() { + return this.name; + } + + @ApiModelProperty(position = 7, required = true, value = "Edge type", example = "Silos") + public String getType() { + return this.type; + } + + @ApiModelProperty(position = 8, value = "Label that may be used in widgets", example = "Silo Edge on far field") + public String getLabel() { + return this.label; + } + @Override public String getSearchText() { return getName(); } + + @ApiModelProperty(position = 9, required = true, value = "Edge routing key ('username') to authorize on cloud") + public String getRoutingKey() { + return this.routingKey; + } + + @ApiModelProperty(position = 10, required = true, value = "Edge secret ('password') to authorize on cloud") + public String getSecret() { + return this.secret; + } + + @ApiModelProperty(position = 11, required = true, value = "Edge license key obtained from license portal", example = "AgcnI24Z06XC&m6Sxsdgf") + public String getEdgeLicenseKey() { + return this.edgeLicenseKey; + } + + @ApiModelProperty(position = 12, required = true, value = "Edge uses this cloud URL to activate and periodically check it's license", example = "https://thingsboard.cloud") + public String getCloudEndpoint() { + return this.cloudEndpoint; + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java index 0da7fd08af..e5c941709c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.edge; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.relation.EntityRelation; @@ -28,8 +29,11 @@ import java.util.List; @Data public class EdgeSearchQuery { + @ApiModelProperty(position = 3, value = "Main search parameters.") private RelationsSearchParameters parameters; + @ApiModelProperty(position = 1, value = "Type of the relation between root entity and edge (e.g. 'Contains' or 'Manages').") private String relationType; + @ApiModelProperty(position = 2, value = "Array of edge types to filter the related entities (e.g. 'Silos', 'Stores').") private List edgeTypes; public EntityRelationsQuery toEntitySearchQuery() { diff --git a/ui-ngx/src/assets/locale/locale.constant-de_DE.json b/ui-ngx/src/assets/locale/locale.constant-de_DE.json index bf8f10ab73..00cd06c893 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -737,7 +737,7 @@ "close": "Dialog schließen" }, "edge": { - "edge": "Rand", + "edge": "Edge", "edge-instances": "Kanteninstanzen", "edge-file": "Edge-Datei", "management": "Rand verwalten", From 757eef1cfa64d0e982bb2f0a9701faf187af882c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 29 Oct 2021 10:50:43 +0300 Subject: [PATCH 174/303] Fixed constants for edge assing/unassign --- .../org/thingsboard/server/controller/AssetController.java | 4 ++-- .../thingsboard/server/controller/ControllerConstants.java | 4 ++-- .../thingsboard/server/controller/DashboardController.java | 4 ++-- .../org/thingsboard/server/controller/DeviceController.java | 4 ++-- .../thingsboard/server/controller/EntityViewController.java | 4 ++-- .../thingsboard/server/controller/RuleChainController.java | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index f7098868d8..e10cd18fe4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -542,7 +542,7 @@ public class AssetController extends BaseController { notes = "Creates assignment of an existing asset to an instance of The Edge. " + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive a copy of assignment asset " + - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once asset will be delivered to edge service, it's going to be available for usage on remote edge instance.", produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -582,7 +582,7 @@ public class AssetController extends BaseController { notes = "Clears assignment of the asset to the edge. " + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive an 'unassign' command to remove asset " + - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once 'unassign' command will be delivered to edge service, it's going to remove asset locally.", produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index 97c2854b89..bf3bcb8afa 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -129,9 +129,9 @@ public class ControllerConstants { protected static final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried."; protected static final String EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Unassignment works in async way - first, 'unassign' notification event pushed to edge queue on platform. "; - protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; + protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform). "; protected static final String EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Assignment works in async way - first, notification event pushed to edge service queue on platform. "; - protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)"; + protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform). "; protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n"; protected static final String MARKDOWN_CODE_BLOCK_END = "\n```"; diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 9035e74d54..4bc23f3fb0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -830,7 +830,7 @@ public class DashboardController extends BaseController { notes = "Creates assignment of an existing dashboard to an instance of The Edge. " + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive a copy of assignment dashboard " + - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once dashboard will be delivered to edge service, it's going to be available for usage on remote edge instance." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @@ -871,7 +871,7 @@ public class DashboardController extends BaseController { notes = "Clears assignment of the dashboard to the edge. " + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive an 'unassign' command to remove dashboard " + - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once 'unassign' command will be delivered to edge service, it's going to remove dashboard locally." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) 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 e50ee8f429..4d4c0215d8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -852,7 +852,7 @@ public class DeviceController extends BaseController { notes = "Creates assignment of an existing device to an instance of The Edge. " + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive a copy of assignment device " + - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once device will be delivered to edge service, it's going to be available for usage on remote edge instance." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -895,7 +895,7 @@ public class DeviceController extends BaseController { notes = "Clears assignment of the device to the edge. " + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive an 'unassign' command to remove device " + - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once 'unassign' command will be delivered to edge service, it's going to remove device locally." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java index 431abbd1be..40e6f65e0d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -711,7 +711,7 @@ public class EntityViewController extends BaseController { notes = "Creates assignment of an existing entity view to an instance of The Edge. " + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive a copy of assignment entity view " + - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once entity view will be delivered to edge service, it's going to be available for usage on remote edge instance.", produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -748,7 +748,7 @@ public class EntityViewController extends BaseController { notes = "Clears assignment of the entity view to the edge. " + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive an 'unassign' command to remove entity view " + - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once 'unassign' command will be delivered to edge service, it's going to remove entity view locally.", produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 5f12e3732c..15c88c676c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -602,7 +602,7 @@ public class RuleChainController extends BaseController { notes = "Creates assignment of an existing rule chain to an instance of The Edge. " + EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive a copy of assignment rule chain " + - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once rule chain will be delivered to edge service, it's going to start processing messages locally. " + "\n\nOnly rule chain with type 'EDGE' can be assigned to edge." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @@ -643,7 +643,7 @@ public class RuleChainController extends BaseController { notes = "Clears assignment of the rule chain to the edge. " + EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION + "Second, remote edge service will receive an 'unassign' command to remove rule chain " + - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " + + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + "Third, once 'unassign' command will be delivered to edge service, it's going to remove rule chain locally." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") From 9c38756eb3c7109b9745a4195d5f28e2b81b56bb Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 13 Oct 2021 12:14:18 +0300 Subject: [PATCH 175/303] Add input field no data to display alternative message --- .../home/components/widget/widget-config.component.html | 6 ++++++ .../home/components/widget/widget-config.component.ts | 2 ++ .../modules/home/components/widget/widget.component.html | 3 +-- .../app/modules/home/components/widget/widget.component.ts | 5 +++++ .../app/modules/home/models/dashboard-component.models.ts | 3 +++ ui-ngx/src/app/shared/models/widget.models.ts | 1 + ui-ngx/src/assets/locale/locale.constant-en_US.json | 3 ++- ui-ngx/src/assets/locale/locale.constant-ru_RU.json | 3 ++- ui-ngx/src/assets/locale/locale.constant-uk_UA.json | 3 ++- 9 files changed, 24 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 555e489afa..761603a3ee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -306,6 +306,12 @@
    +
    + + widget-config.no-data-display-message + + +
    diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 48ed4bf700..7d779a3a6c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -209,6 +209,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont titleStyle: [null, []], units: [null, []], decimals: [null, [Validators.min(0), Validators.max(15), Validators.pattern(/^\d*$/)]], + noDataDisplayMessage: [null, []], showLegend: [null, []], legendConfig: [null, []] }); @@ -411,6 +412,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont }, units: config.units, decimals: config.decimals, + noDataDisplayMessage: isDefined(config.noDataDisplayMessage) ? config.noDataDisplayMessage : '', showLegend: isDefined(config.showLegend) ? config.showLegend : this.widgetType === widgetType.timeseries, legendConfig: config.legendConfig || defaultLegendConfig(this.widgetType) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.html b/ui-ngx/src/app/modules/home/components/widget/widget.component.html index 0b0498d562..fcaede8fc9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.html @@ -39,8 +39,7 @@
    widget.no-data + class="tb-absolute-fill">{{ noDataDisplayMessageText }}
    diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 920f6721b9..b95d96064c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -361,6 +361,11 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI }, 0); } + get noDataDisplayMessageText(): string { + const noDataDisplayMessage = isNotEmptyStr(this.widget.config.noDataDisplayMessage) ? this.widget.config.noDataDisplayMessage : '{i18n:widget.no-data}'; + return this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage); + } + ngAfterViewInit(): void { } diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 2a3d92cf31..efbb3a5c23 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -323,6 +323,8 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { dropShadow: boolean; enableFullscreen: boolean; + noDataDisplayMessage: string; + hasTimewindow: boolean; hasAggregation: boolean; @@ -411,6 +413,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { this.titleIcon = isDefined(this.widget.config.titleIcon) ? this.widget.config.titleIcon : ''; this.showTitleIcon = isDefined(this.widget.config.showTitleIcon) ? this.widget.config.showTitleIcon : false; + this.noDataDisplayMessage = isDefined(this.widget.config.noDataDisplayMessage) ? this.widget.config.noDataDisplayMessage : ''; this.titleIconStyle = {}; if (this.widget.config.iconColor) { this.titleIconStyle.color = this.widget.config.iconColor; diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 687566afa7..0b0353c7a9 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -509,6 +509,7 @@ export interface WidgetConfig { titleStyle?: {[klass: string]: any}; units?: string; decimals?: number; + noDataDisplayMessage?: string; actions?: {[actionSourceId: string]: Array}; settings?: any; alarmSource?: Datasource; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 7451e2c1b9..4528890b14 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3077,7 +3077,8 @@ "icon-color": "Icon color", "icon-size": "Icon size", "advanced-settings": "Advanced settings", - "data-settings": "Data settings" + "data-settings": "Data settings", + "no-data-display-message": "\"No data to display\" alternative message" }, "widget-type": { "import": "Import widget type", diff --git a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json index d6fefd0e55..66d99281bb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json @@ -1679,7 +1679,8 @@ "icon-color": "Цвет иконки", "icon-size": "Размер иконки", "advanced-settings": "Расширенные настройки", - "data-settings": "Настройки данных" + "data-settings": "Настройки данных", + "no-data-display-message": "\"Нет данных для отображения\" альтернативный текст" }, "widget-type": { "import": "Импортировать тип виджета", diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index 0031ca2ad0..43691918dd 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -2251,7 +2251,8 @@ "icon-color": "Колір іконки", "icon-size": "Розмір іконки", "advanced-settings": "Розширені налаштування", - "data-settings": "Налаштування даних" + "data-settings": "Налаштування даних", + "no-data-display-message": "\"Немає данних для відображення\" альтернативний текст" }, "widget-type": { "import": "Імпортувати тип віджета", From dd29490dd7a9e126db08dda68ffc85708a8b9b14 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 13 Oct 2021 12:47:47 +0300 Subject: [PATCH 176/303] Add no data display message to entities and alarm tables --- .../widget/lib/alarms-table-widget.component.html | 2 +- .../components/widget/lib/alarms-table-widget.component.ts | 7 ++++++- .../widget/lib/entities-table-widget.component.html | 2 +- .../widget/lib/entities-table-widget.component.ts | 7 ++++++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html index 7c88c79e2b..a86da23f59 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html @@ -136,7 +136,7 @@ alarm.no-alarms-prompt + class="no-data-found">{{ noDataDisplayMessageText }} {{ 'common.loading' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index bcdc396c79..11eeb37cab 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -39,7 +39,7 @@ import { createLabelFromDatasource, deepClone, hashCode, - isDefined, + isDefined, isNotEmptyStr, isNumber, isObject, isUndefined @@ -265,6 +265,11 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, } } + get noDataDisplayMessageText() { + const noDataDisplayMessage = isNotEmptyStr(this.ctx.widgetConfig.noDataDisplayMessage) ? this.ctx.widgetConfig.noDataDisplayMessage : '{i18n:alarm.no-alarms-prompt}'; + return this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage); + } + ngAfterViewInit(): void { fromEvent(this.searchInputField.nativeElement, 'keyup') .pipe( diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html index ddf4972dc7..74ccd53ec2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html @@ -95,7 +95,7 @@ entity.no-entities-prompt + class="no-data-found">{{ noDataDisplayMessageText }} {{ 'common.loading' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index f1617eb288..7c0f1794c5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -44,7 +44,7 @@ import { createLabelFromDatasource, deepClone, hashCode, - isDefined, + isDefined, isNotEmptyStr, isNumber, isObject, isUndefined @@ -211,6 +211,11 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.ctx.updateWidgetParams(); } + get noDataDisplayMessageText() { + const noDataDisplayMessage = isNotEmptyStr(this.ctx.widgetConfig.noDataDisplayMessage) ? this.ctx.widgetConfig.noDataDisplayMessage : '{i18n:entity.no-entities-prompt}'; + return this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage); + } + ngAfterViewInit(): void { fromEvent(this.searchInputField.nativeElement, 'keyup') .pipe( From a8ec0c28078ca435b1bc7cb96456931df036e191 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 20 Oct 2021 12:28:08 +0300 Subject: [PATCH 177/303] Change custom translation method for default text --- .../components/widget/lib/alarms-table-widget.component.ts | 6 ++++-- .../widget/lib/entities-table-widget.component.ts | 6 ++++-- .../app/modules/home/components/widget/widget.component.ts | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 11eeb37cab..d6d754f62b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -266,8 +266,10 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, } get noDataDisplayMessageText() { - const noDataDisplayMessage = isNotEmptyStr(this.ctx.widgetConfig.noDataDisplayMessage) ? this.ctx.widgetConfig.noDataDisplayMessage : '{i18n:alarm.no-alarms-prompt}'; - return this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage); + const noDataDisplayMessage = this.ctx.widgetConfig.noDataDisplayMessage; + return isNotEmptyStr(noDataDisplayMessage) + ? this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage) + : this.translate.instant('alarm.no-alarms-prompt'); } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index 7c0f1794c5..d068a1010e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -212,8 +212,10 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni } get noDataDisplayMessageText() { - const noDataDisplayMessage = isNotEmptyStr(this.ctx.widgetConfig.noDataDisplayMessage) ? this.ctx.widgetConfig.noDataDisplayMessage : '{i18n:entity.no-entities-prompt}'; - return this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage); + const noDataDisplayMessage = this.ctx.widgetConfig.noDataDisplayMessage; + return isNotEmptyStr(noDataDisplayMessage) + ? this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage) + : this.translate.instant('entity.no-entities-prompt'); } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index b95d96064c..257c7bd3a2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -362,8 +362,10 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI } get noDataDisplayMessageText(): string { - const noDataDisplayMessage = isNotEmptyStr(this.widget.config.noDataDisplayMessage) ? this.widget.config.noDataDisplayMessage : '{i18n:widget.no-data}'; - return this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage); + const noDataDisplayMessage = this.widget.config.noDataDisplayMessage; + return isNotEmptyStr(noDataDisplayMessage) + ? this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage) + : this.translate.instant('widget.no-data'); } ngAfterViewInit(): void { From 26ba3abab0e3c15504cc119d3d63553d528b8c45 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 29 Oct 2021 12:10:57 +0300 Subject: [PATCH 178/303] Change translation --- ui-ngx/src/assets/locale/locale.constant-el_GR.json | 4 ++-- ui-ngx/src/assets/locale/locale.constant-fr_FR.json | 4 ++-- ui-ngx/src/assets/locale/locale.constant-ka_GE.json | 2 +- ui-ngx/src/assets/locale/locale.constant-lv_LV.json | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-el_GR.json b/ui-ngx/src/assets/locale/locale.constant-el_GR.json index 153621e69a..e178627eb2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-el_GR.json +++ b/ui-ngx/src/assets/locale/locale.constant-el_GR.json @@ -596,8 +596,8 @@ "make-private-dashboard-title": "Είστε σίγουροι ότι θέλετε να κάνετε το dashboard '{{dashboardTitle}}' ιδιωτικό", "make-private-dashboard-text": "Μετά την επιβεβαίωση το dashboard θα γίνουν ιδιωτικά και δεν θα είναι διαθέσιμα από τρίτους.", "make-private-dashboard": "Κάνε το dashboard ιδιωτικό", - "socialshare-text": "'{{dashboardTitle}}' powered by EyeTech", - "socialshare-title": "'{{dashboardTitle}}' powered by EyeTech", + "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", + "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard", "select-dashboard": "Επιλογή dashboard", "no-dashboards-matching": "Δεν βρέθηκαν dashboards που να αντιστοιχούν σε '{{entity}}'.", "dashboard-required": "Απαιτείται dashboard.", diff --git a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json index facf0f8534..b7f6dfebfb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -1470,7 +1470,7 @@ "rulechain-required": "Chaîne de règles requise", "rulechains": "Chaînes de règles", "select-rulechain": "Sélectionner la chaîne de règles", - "set-root": "Rend la chaîne de règles racine (root) ", + "set-root": "Rendre la chaîne de règles racine (root) ", "set-root-rulechain-text": "Après la confirmation, la chaîne de règles deviendra racine (root) et gérera tous les messages de transport entrants.", "set-root-rulechain-title": "Voulez-vous vraiment que la chaîne de règles '{{ruleChainName}} soit racine (root) ?", "system": "Système", @@ -1498,7 +1498,7 @@ "edge-template-root": "Racine du modèle", "search": "Rechercher des chaînes de règles", "selected-rulechains": "{count, plural, 1 {1 rule chain} other {# rule chains} } sélectionné", - "open-rulechain": "Chaîne de règles ouverte", + "open-rulechain": "Ouvrir la Chaîne de règles", "assign-to-edge": "Attribuer à Bordure", "edge-rulechain": "Chaîne de règles Bordure", "unassign-rulechains-from-edge-title": "Voulez-vous vraiment annuler l'attribution de {count, plural, 1 {1 rulechain} other {# rulechains} }?" diff --git a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json index f18d62cad2..94da40c3c1 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json +++ b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json @@ -492,7 +492,7 @@ "make-private-dashboard-text": "დადასტურების შემდეგ დეშბორდი გახდება პრივატული და აღარ იქნება ხელმისაწვდომი სხვა მომხმარებლებისთვის", "make-private-dashboard": "აქციე დეშბორდი პრივატულად", "socialshare-text": "სოციალური ტექსტი", - "socialshare-title": "'{{dashboardTitle}}' Powered by Giot", + "socialshare-title": "'{{dashboardTitle}}' Powered by ThingsBoard", "select-dashboard": "აირჩიე დეშბორდი", "no-dashboards-matching": "'{{entity}}'-ს მზგავსი დეშბორდი არ იქნა ნაპოვნი.", "dashboard-required": "დეშბორდი აუცილებელია", diff --git a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json index 7daa8e5802..3563aef32e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json +++ b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json @@ -453,8 +453,8 @@ "make-private-dashboard-title": "Vai esat pārliecināts, ka vēlaties veidot paneli '{{dashboardTitle}}' privātu?", "make-private-dashboard-text": "Pēc apstiprinājuma panelis būs privāts un nebūs pieejams citiem.", "make-private-dashboard": "Veidot paneli privātu", - "socialshare-text": "'{{dashboardTitle}}' atbalsts no TeT", - "socialshare-title": "'{{dashboardTitle}}' atbalsts no TeT", + "socialshare-text": "'{{dashboardTitle}}' atbalsts no ThingsBoard", + "socialshare-title": "'{{dashboardTitle}}' atbalsts no ThingsBoard", "select-dashboard": "Atlasīt paneli", "no-dashboards-matching": "Nav atbilstoši paneļi '{{entity}}' atrasti.", "dashboard-required": "Penelis ir nepieciešams.", From e8163a01fffc97594fe87d52a5d68ae471f3323c Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 29 Oct 2021 12:21:14 +0300 Subject: [PATCH 179/303] Change example for error-verification-url in CR locale --- ui-ngx/src/assets/locale/locale.constant-el_GR.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-el_GR.json b/ui-ngx/src/assets/locale/locale.constant-el_GR.json index e178627eb2..92988533a3 100644 --- a/ui-ngx/src/assets/locale/locale.constant-el_GR.json +++ b/ui-ngx/src/assets/locale/locale.constant-el_GR.json @@ -2496,7 +2496,7 @@ "domain-name": "Όνομα Domain", "help-link-base-url": "Base url για συνδέσμους βοηθείας", "enable-help-links": "Ενεργοποίηση συνδέσμων βοηθείας", - "error-verification-url": "Ένα όνομα domain δεν πρέπει να περιέχει σύμβολα '/' και ':'. Παράδειγμα: gprs.cloud", + "error-verification-url": "Ένα όνομα domain δεν πρέπει να περιέχει σύμβολα '/' και ':'. Παράδειγμα: thingsboard.io", "show-platform-name-version": "Εμφάνιση ονόματος και έκδοσης πλατφόρμας", "platform-name": "Όνομα πλατφόρμας", "platform-version": "Έκδοση πλατφόρμας", From 03fb9dcd7f062db9a59a8f88c99c8272fd3c1f22 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 29 Oct 2021 15:54:54 +0300 Subject: [PATCH 180/303] Fix UUID link --- .../org/thingsboard/server/controller/AlarmController.java | 3 ++- .../org/thingsboard/server/controller/AssetController.java | 7 ++++--- .../thingsboard/server/controller/ControllerConstants.java | 1 + .../thingsboard/server/controller/DeviceController.java | 5 +++-- .../server/controller/DeviceProfileController.java | 3 ++- .../org/thingsboard/server/controller/EdgeController.java | 3 ++- .../server/controller/OtaPackageController.java | 3 ++- .../thingsboard/server/controller/RuleChainController.java | 3 ++- .../server/controller/TbResourceController.java | 3 ++- .../thingsboard/server/controller/TenantController.java | 3 ++- .../server/controller/TenantProfileController.java | 3 ++- .../org/thingsboard/server/controller/UserController.java | 3 ++- .../server/controller/WidgetTypeController.java | 3 ++- .../server/controller/WidgetsBundleController.java | 3 ++- 14 files changed, 30 insertions(+), 16 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index d376f5984f..9920e232de 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -66,6 +66,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -120,7 +121,7 @@ public class AlarmController extends BaseController { @ApiOperation(value = "Create or update Alarm (saveAlarm)", notes = "Creates or Updates the Alarm. " + - "When creating alarm, platform generates Alarm Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "When creating alarm, platform generates Alarm Id as " + UUID_WIKI_LINK + "The newly created Alarm id will be present in the response. Specify existing Alarm id to update the alarm. " + "Referencing non-existing Alarm Id will cause 'Not Found' error. " + "\n\nPlatform also deduplicate the alarms based on the entity id of originator and alarm 'type'. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index e10cd18fe4..9e50b6171e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -84,6 +84,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; import static org.thingsboard.server.controller.EdgeController.EDGE_ID; import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; @@ -136,7 +137,7 @@ public class AssetController extends BaseController { } @ApiOperation(value = "Create Or Update Asset (saveAsset)", - notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address) " + + notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as " + UUID_WIKI_LINK + "The newly created Asset id will be present in the response. " + "Specify existing Asset id to update the asset. " + "Referencing non-existing Asset Id will cause 'Not Found' error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @@ -378,9 +379,9 @@ public class AssetController extends BaseController { notes = "Requested asset must be owned by tenant that the user belongs to. " + "Asset name is an unique property of asset. So it can be used to identify the asset." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET) + @RequestMapping(value = "/tenant/assets/name", method = RequestMethod.GET) @ResponseBody - public Asset getTenantAsset( + public Asset getTenantAssetByName( @ApiParam(value = ASSET_NAME_DESCRIPTION) @RequestParam String assetName) throws ThingsboardException { try { diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index bf3bcb8afa..94cfd8da4a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -18,6 +18,7 @@ package org.thingsboard.server.controller; public class ControllerConstants { protected static final String NEW_LINE = "\n\n"; + protected static final String UUID_WIKI_LINK = "[time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address%29) "; protected static final int DEFAULT_PAGE_SIZE = 1000; protected static final String ENTITY_TYPE = "entityType"; protected static final String CUSTOMER_ID = "customerId"; 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 0bb2973fc5..6ea6bdd880 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -112,6 +112,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERT import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; import static org.thingsboard.server.controller.EdgeController.EDGE_ID; @RestController @@ -166,7 +167,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Create Or Update Device (saveDevice)", - notes = "Create or update the Device. When creating device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK + "Device credentials are also generated if not provided in the 'accessToken' request parameter. " + "The newly created device id will be present in the response. " + "Specify existing Device id to update the device. " + @@ -203,7 +204,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Create Device (saveDevice) with credentials ", - notes = "Create or update the Device. When creating device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK + "Requires to provide the Device Credentials object as well. Useful to create device and credentials in one request. " + "You may find the example of LwM2M device and RPK credentials below: \n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN + diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 6bba29ef9e..c1c8743101 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -65,6 +65,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERT import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TRANSPORT_TYPE_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -186,7 +187,7 @@ public class DeviceProfileController extends BaseController { } @ApiOperation(value = "Create Or Update Device Profile (saveDeviceProfile)", - notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as " + UUID_WIKI_LINK + "The newly created device profile id will be present in the response. " + "Specify existing device profile id to update the device profile. " + "Referencing non-existing device profile Id will cause 'Not Found' error. " + NEW_LINE + diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 4b57c8128d..eec1098fbd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -84,6 +84,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -149,7 +150,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Create Or Update Edge (saveEdge)", - notes = "Create or update the Edge. When creating edge, platform generates Edge Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Edge. When creating edge, platform generates Edge Id as " + UUID_WIKI_LINK + "The newly created edge id will be present in the response. " + "Specify existing Edge id to update the edge. " + "Referencing non-existing Edge Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java index 593914bc4c..71fdcae1c8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java +++ b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java @@ -64,6 +64,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @Slf4j @RestController @@ -138,7 +139,7 @@ public class OtaPackageController extends BaseController { } @ApiOperation(value = "Create Or Update OTA Package Info (saveOtaPackageInfo)", - notes = "Create or update the OTA Package Info. When creating OTA Package Info, platform generates OTA Package id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the OTA Package Info. When creating OTA Package Info, platform generates OTA Package id as " + UUID_WIKI_LINK + "The newly created OTA Package id will be present in the response. " + "Specify existing OTA Package id to update the OTA Package Info. " + "Referencing non-existing OTA Package Id will cause 'Not Found' error. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 15c88c676c..128e2abd23 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -101,6 +101,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @Slf4j @RestController @@ -186,7 +187,7 @@ public class RuleChainController extends BaseController { } @ApiOperation(value = "Create Or Update Rule Chain (saveRuleChain)", - notes = "Create or update the Rule Chain. When creating Rule Chain, platform generates Rule Chain Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Rule Chain. When creating Rule Chain, platform generates Rule Chain Id as " + UUID_WIKI_LINK + "The newly created Rule Chain Id will be present in the response. " + "Specify existing Rule Chain id to update the rule chain. " + "Referencing non-existing rule chain Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java index 3f083c3572..4d0c088194 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java @@ -62,6 +62,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @Slf4j @RestController @@ -131,7 +132,7 @@ public class TbResourceController extends BaseController { } @ApiOperation(value = "Create Or Update Resource (saveResource)", - notes = "Create or update the Resource. When creating the Resource, platform generates Resource id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Resource. When creating the Resource, platform generates Resource id as " + UUID_WIKI_LINK + "The newly created Resource id will be present in the response. " + "Specify existing Resource id to update the Resource. " + "Referencing non-existing Resource Id will cause 'Not Found' error. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index edde16d6e5..0cfc8f3865 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -57,6 +57,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PA import static org.thingsboard.server.controller.ControllerConstants.TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.TENANT_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.TENANT_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -111,7 +112,7 @@ public class TenantController extends BaseController { } @ApiOperation(value = "Create Or update Tenant (saveTenant)", - notes = "Create or update the Tenant. When creating tenant, platform generates Tenant Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Tenant. When creating tenant, platform generates Tenant Id as " + UUID_WIKI_LINK + "Default Rule Chain and Device profile are also generated for the new tenants automatically. " + "The newly created Tenant Id will be present in the response. " + "Specify existing Tenant Id id to update the Tenant. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index ab52e8ebd4..01023edf6d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -53,6 +53,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFI import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -110,7 +111,7 @@ public class TenantProfileController extends BaseController { } @ApiOperation(value = "Create Or update Tenant Profile (saveTenantProfile)", - notes = "Create or update the Tenant Profile. When creating tenant profile, platform generates Tenant Profile Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Tenant Profile. When creating tenant profile, platform generates Tenant Profile Id as " + UUID_WIKI_LINK + "The newly created Tenant Profile Id will be present in the response. " + "Specify existing Tenant Profile Id id to update the Tenant Profile. " + "Referencing non-existing Tenant Profile Id will cause 'Not Found' error. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index d768a42e16..e83bc8970c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -81,6 +81,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CU import static org.thingsboard.server.controller.ControllerConstants.USER_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.USER_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.USER_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RequiredArgsConstructor @RestController @@ -174,7 +175,7 @@ public class UserController extends BaseController { } @ApiOperation(value = "Save Or update User (saveUser)", - notes = "Create or update the User. When creating user, platform generates User Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the User. When creating user, platform generates User Id as " + UUID_WIKI_LINK + "The newly created User Id will be present in the response. " + "Specify existing User Id to update the device. " + "Referencing non-existing User Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index a899f4cce2..b7f8b28b28 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -45,6 +45,7 @@ import java.util.List; import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER; import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; import static org.thingsboard.server.controller.ControllerConstants.WIDGET_TYPE_ID_PARAM_DESCRIPTION; @Slf4j @@ -78,7 +79,7 @@ public class WidgetTypeController extends BaseController { @ApiOperation(value = "Create Or Update Widget Type (saveWidgetType)", notes = "Create or update the Widget Type. " + WIDGET_TYPE_DESCRIPTION + " " + - "When creating the Widget Type, platform generates Widget Type Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "When creating the Widget Type, platform generates Widget Type Id as " + UUID_WIKI_LINK + "The newly created Widget Type Id will be present in the response. " + "Specify existing Widget Type id to update the Widget Type. " + "Referencing non-existing Widget Type Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index a6cc14dce1..36999950c1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -49,6 +49,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION; @@ -79,7 +80,7 @@ public class WidgetsBundleController extends BaseController { @ApiOperation(value = "Create Or Update Widget Bundle (saveWidgetsBundle)", notes = "Create or update the Widget Bundle. " + WIDGET_BUNDLE_DESCRIPTION + " " + - "When creating the bundle, platform generates Widget Bundle Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "When creating the bundle, platform generates Widget Bundle Id as " + UUID_WIKI_LINK + "The newly created Widget Bundle Id will be present in the response. " + "Specify existing Widget Bundle id to update the Widget Bundle. " + "Referencing non-existing Widget Bundle Id will cause 'Not Found' error." + From 3e67dc1c00117d6ef901df1ae588265a3f05623f Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 29 Oct 2021 15:58:05 +0300 Subject: [PATCH 181/303] Restore the getTenantAsset API call signature --- .../org/thingsboard/server/controller/AssetController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index 9e50b6171e..b03e446c7b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -379,9 +379,9 @@ public class AssetController extends BaseController { notes = "Requested asset must be owned by tenant that the user belongs to. " + "Asset name is an unique property of asset. So it can be used to identify the asset." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/tenant/assets/name", method = RequestMethod.GET) + @RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET) @ResponseBody - public Asset getTenantAssetByName( + public Asset getTenantAsset( @ApiParam(value = ASSET_NAME_DESCRIPTION) @RequestParam String assetName) throws ThingsboardException { try { From f005f82fe03cb56ebf93982f63411b3bc85cd572 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Fri, 29 Oct 2021 13:53:19 +0300 Subject: [PATCH 182/303] fixed rest json converter to parse json array --- .../org/thingsboard/rest/client/utils/RestJsonConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/utils/RestJsonConverter.java b/rest-client/src/main/java/org/thingsboard/rest/client/utils/RestJsonConverter.java index 9d17c6d84a..0b28dda9f0 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/utils/RestJsonConverter.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/utils/RestJsonConverter.java @@ -71,7 +71,7 @@ public class RestJsonConverter { } private static KvEntry parseValue(String key, JsonNode value) { - if (!value.isObject()) { + if (!value.isContainerNode()) { if (value.isBoolean()) { return new BooleanDataEntry(key, value.asBoolean()); } else if (value.isNumber()) { From 8914cdb70784fec737f49a23c1a8437739fb9985 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Mon, 1 Nov 2021 13:23:38 +0200 Subject: [PATCH 183/303] fixed the reprocessing logic for rule engine messages when the strategy is not set to reprocess them --- .../TbRuleEngineProcessingStrategyFactory.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java index f29377445d..f2ee70f333 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.queue.processing; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.TbMsgCallback; import org.thingsboard.server.gen.transport.TransportProtos; @@ -77,6 +78,7 @@ public class TbRuleEngineProcessingStrategyFactory { @Override public TbRuleEngineProcessingDecision analyze(TbRuleEngineProcessingResult result) { if (result.isSuccess()) { + log.debug("[{}] The result of the msg pack processing is successful, going to proceed with processing of the following msgs", queueName); return new TbRuleEngineProcessingDecision(true, null); } else { if (retryCount == 0) { @@ -91,6 +93,7 @@ public class TbRuleEngineProcessingStrategyFactory { log.debug("[{}] Skip reprocess of the rule engine pack due to max allowed failure percentage", queueName); return new TbRuleEngineProcessingDecision(true, null); } else { + log.debug("[{}] The result of msg pack processing is unsuccessful, checking unprocessed msgs and going to reprocess them", queueName); ConcurrentMap> toReprocess = new ConcurrentHashMap<>(initialTotalCount); if (retryFailed) { result.getFailedMap().forEach(toReprocess::put); @@ -101,6 +104,15 @@ public class TbRuleEngineProcessingStrategyFactory { if (retrySuccessful) { result.getSuccessMap().forEach(toReprocess::put); } + if (CollectionUtils.isEmpty(toReprocess)) { + log.debug("[{}] Stopping the reprocessing logic due to reprocessing map is empty", queueName); + if (retryFailed) { + log.debug("[{}] Probably there are timedOut msgs, but the strategy is not set to reprocess them. Reprocess of the failed msgs is set", queueName); + } else if (retryTimeout) { + log.debug("[{}] Probably there are failed msgs, but the strategy is not set to reprocess them. Reprocess of the timedOut msgs is set", queueName); + } + return new TbRuleEngineProcessingDecision(true, null); + } log.debug("[{}] Going to reprocess {} messages", queueName, toReprocess.size()); if (log.isTraceEnabled()) { toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); From 467a94f6882633c9c2315d598fd032531639e17d Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 1 Nov 2021 13:46:44 +0200 Subject: [PATCH 184/303] added new efento endpoints support --- .../transport/coap/CoapTransportService.java | 13 ++++-- .../efento/CoapEfentoTransportResource.java | 40 ++++++++++++++++--- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java index 66fd870dc9..6d7be52ad9 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java @@ -39,7 +39,10 @@ public class CoapTransportService implements TbTransportService { private static final String V1 = "v1"; private static final String API = "api"; private static final String EFENTO = "efento"; - private static final String MEASUREMENTS = "m"; + public static final String MEASUREMENTS = "m"; + public static final String DEVICE_INFO = "i"; + public static final String CONFIGURATION = "c"; + public static final String CURRENT_TIMESTAMP = "t"; @Autowired private CoapServerService coapServerService; @@ -56,9 +59,11 @@ public class CoapTransportService implements TbTransportService { CoapResource api = new CoapResource(API); api.add(new CoapTransportResource(coapTransportContext, coapServerService, V1)); - CoapResource efento = new CoapResource(EFENTO); - CoapEfentoTransportResource efentoMeasurementsTransportResource = new CoapEfentoTransportResource(coapTransportContext, MEASUREMENTS); - efento.add(efentoMeasurementsTransportResource); + CoapEfentoTransportResource efento = new CoapEfentoTransportResource(coapTransportContext, EFENTO); + efento.add(new CoapResource(MEASUREMENTS)); + efento.add(new CoapResource(DEVICE_INFO)); + efento.add(new CoapResource(CONFIGURATION)); + efento.add(new CoapResource(CURRENT_TIMESTAMP)); coapServer.add(api); coapServer.add(efento); coapServer.add(new OtaPackageTransportResource(coapTransportContext, OtaPackageType.FIRMWARE)); diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java index 007b2c7f46..59482d9fc2 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java @@ -41,6 +41,7 @@ import org.thingsboard.server.transport.coap.callback.CoapDeviceAuthCallback; import org.thingsboard.server.transport.coap.callback.CoapOkCallback; import org.thingsboard.server.transport.coap.efento.utils.CoapEfentoUtils; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -48,11 +49,15 @@ import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.TimeUnit; +import static org.thingsboard.server.transport.coap.CoapTransportService.CONFIGURATION; +import static org.thingsboard.server.transport.coap.CoapTransportService.CURRENT_TIMESTAMP; +import static org.thingsboard.server.transport.coap.CoapTransportService.DEVICE_INFO; +import static org.thingsboard.server.transport.coap.CoapTransportService.MEASUREMENTS; + @Slf4j public class CoapEfentoTransportResource extends AbstractCoapTransportResource { - private static final int MEASUREMENTS_POSITION = 2; - private static final String MEASUREMENTS = "m"; + private static final int CHILD_RESOURCE_POSITION = 2; public CoapEfentoTransportResource(CoapTransportContext context, String name) { super(context, name); @@ -63,7 +68,17 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { @Override protected void processHandleGet(CoapExchange exchange) { - exchange.respond(CoAP.ResponseCode.METHOD_NOT_ALLOWED); + Exchange advanced = exchange.advanced(); + Request request = advanced.getRequest(); + List uriPath = request.getOptions().getUriPath(); + boolean validPath = uriPath.size() == CHILD_RESOURCE_POSITION && uriPath.get(1).equals(CURRENT_TIMESTAMP); + if (!validPath) { + exchange.respond(CoAP.ResponseCode.BAD_REQUEST); + } else { + int dateInSec = (int) (System.currentTimeMillis() / 1000); + byte[] bytes = ByteBuffer.allocate(4).putInt(dateInSec).array(); + exchange.respond(CoAP.ResponseCode.CONTENT, bytes); + } } @Override @@ -71,11 +86,26 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { Exchange advanced = exchange.advanced(); Request request = advanced.getRequest(); List uriPath = request.getOptions().getUriPath(); - boolean validPath = uriPath.size() == MEASUREMENTS_POSITION && uriPath.get(1).equals(MEASUREMENTS); - if (!validPath) { + if (uriPath.size() != CHILD_RESOURCE_POSITION) { exchange.respond(CoAP.ResponseCode.BAD_REQUEST); return; } + String requestType = uriPath.get(1); + switch (requestType) { + case MEASUREMENTS: + processMeasurementsRequest(exchange, request); + break; + case DEVICE_INFO: + case CONFIGURATION: + exchange.respond(CoAP.ResponseCode.CREATED); + break; + default: + exchange.respond(CoAP.ResponseCode.BAD_REQUEST); + break; + } + } + + private void processMeasurementsRequest(CoapExchange exchange, Request request) { byte[] bytes = request.getPayload(); try { MeasurementsProtos.ProtoMeasurements protoMeasurements = MeasurementsProtos.ProtoMeasurements.parseFrom(bytes); From c49297b4335c14361637e710d64e3a55aeef0354 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Mon, 1 Nov 2021 14:57:16 +0200 Subject: [PATCH 185/303] logging improvements --- .../TbRuleEngineProcessingStrategyFactory.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java index f2ee70f333..2749dd7fc5 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java @@ -97,19 +97,22 @@ public class TbRuleEngineProcessingStrategyFactory { ConcurrentMap> toReprocess = new ConcurrentHashMap<>(initialTotalCount); if (retryFailed) { result.getFailedMap().forEach(toReprocess::put); + } else if (log.isDebugEnabled() && !result.getFailedMap().isEmpty()) { + log.debug("[{}] Skipped {} failed messages due to the processing strategy configuration", queueName, result.getFailedMap().size()); } if (retryTimeout) { result.getPendingMap().forEach(toReprocess::put); + } else if (log.isDebugEnabled() && !result.getPendingMap().isEmpty()) { + log.debug("[{}] Skipped {} timedOut messages due to the processing strategy configuration", queueName, result.getPendingMap().size()); } if (retrySuccessful) { result.getSuccessMap().forEach(toReprocess::put); + } else if (log.isDebugEnabled() && !result.getSuccessMap().isEmpty()) { + log.debug("[{}] Skipped {} successful messages due to the processing strategy configuration", queueName, result.getSuccessMap().size()); } if (CollectionUtils.isEmpty(toReprocess)) { - log.debug("[{}] Stopping the reprocessing logic due to reprocessing map is empty", queueName); - if (retryFailed) { - log.debug("[{}] Probably there are timedOut msgs, but the strategy is not set to reprocess them. Reprocess of the failed msgs is set", queueName); - } else if (retryTimeout) { - log.debug("[{}] Probably there are failed msgs, but the strategy is not set to reprocess them. Reprocess of the timedOut msgs is set", queueName); + if (log.isDebugEnabled()) { + log.debug("[{}] Stopping the reprocessing logic due to reprocessing map is empty", queueName); } return new TbRuleEngineProcessingDecision(true, null); } From d110f5a005ee0410ebee0c72dd2f55517a68597d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 1 Nov 2021 18:58:11 +0200 Subject: [PATCH 186/303] Update springfox swagger version. --- application/pom.xml | 8 +- .../server/ThingsboardServerApplication.java | 2 - .../server/config/SwaggerConfiguration.java | 221 ++++++++++++++++-- .../ThingsboardSecurityConfiguration.java | 1 + .../thingsboard/server/config/WebConfig.java | 10 +- .../controller/ControllerConstants.java | 1 + .../controller/RuleChainController.java | 3 +- .../controller/WidgetsBundleController.java | 2 +- .../extractor/JwtHeaderTokenExtractor.java | 5 +- .../security/auth/rest/LoginRequest.java | 7 + .../security/auth/rest/LoginResponse.java | 34 +++ .../src/main/resources/thingsboard.yml | 6 +- pom.xml | 18 +- 13 files changed, 273 insertions(+), 45 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginResponse.java diff --git a/application/pom.xml b/application/pom.xml index 3378d52459..fd90d00d34 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -250,8 +250,8 @@ grpc-stub - io.springfox - springfox-swagger2 + org.thingsboard + springfox-boot-starter com.sun.winsw @@ -319,10 +319,6 @@ org.javadelight delight-nashorn-sandbox - - io.springfox.ui - springfox-swagger-ui-rfc6570 - org.passay passay diff --git a/application/src/main/java/org/thingsboard/server/ThingsboardServerApplication.java b/application/src/main/java/org/thingsboard/server/ThingsboardServerApplication.java index 4d15894387..8d39cf65ce 100644 --- a/application/src/main/java/org/thingsboard/server/ThingsboardServerApplication.java +++ b/application/src/main/java/org/thingsboard/server/ThingsboardServerApplication.java @@ -20,13 +20,11 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; -import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.Arrays; @SpringBootConfiguration @EnableAsync -@EnableSwagger2 @EnableScheduling @ComponentScan({"org.thingsboard.server"}) public class ThingsboardServerApplication { diff --git a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java index 50532c435e..ba3771616a 100644 --- a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java @@ -18,27 +18,60 @@ package org.thingsboard.server.config; import com.fasterxml.classmate.ResolvedType; import com.fasterxml.classmate.TypeResolver; import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.base.Predicate; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.exception.ThingsboardErrorResponse; +import org.thingsboard.server.service.security.auth.rest.LoginRequest; +import org.thingsboard.server.service.security.auth.rest.LoginResponse; import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.schema.AlternateTypeRule; +import springfox.documentation.builders.OperationBuilder; +import springfox.documentation.builders.RepresentationBuilder; +import springfox.documentation.builders.RequestParameterBuilder; +import springfox.documentation.builders.ResponseBuilder; +import springfox.documentation.service.ApiDescription; import springfox.documentation.service.ApiInfo; -import springfox.documentation.service.ApiKey; +import springfox.documentation.service.ApiListing; import springfox.documentation.service.AuthorizationScope; import springfox.documentation.service.Contact; +import springfox.documentation.service.HttpLoginPasswordScheme; +import springfox.documentation.service.ParameterType; +import springfox.documentation.service.Response; import springfox.documentation.service.SecurityReference; +import springfox.documentation.service.SecurityScheme; +import springfox.documentation.service.Tag; import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.ApiListingBuilderPlugin; +import springfox.documentation.spi.service.ApiListingScannerPlugin; +import springfox.documentation.spi.service.contexts.ApiListingContext; +import springfox.documentation.spi.service.contexts.DocumentationContext; +import springfox.documentation.spi.service.contexts.OperationContext; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator; +import springfox.documentation.swagger.common.SwaggerPluginSupport; +import springfox.documentation.swagger.web.DocExpansion; +import springfox.documentation.swagger.web.ModelRendering; +import springfox.documentation.swagger.web.OperationsSorter; +import springfox.documentation.swagger.web.UiConfiguration; +import springfox.documentation.swagger.web.UiConfigurationBuilder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; -import static com.google.common.base.Predicates.and; -import static com.google.common.base.Predicates.not; import static com.google.common.collect.Lists.newArrayList; +import static java.util.function.Predicate.not; +import static springfox.documentation.builders.PathSelectors.any; import static springfox.documentation.builders.PathSelectors.regex; @Configuration @@ -67,6 +100,9 @@ public class SwaggerConfiguration { @Value("${swagger.version}") private String version; + @Autowired + private CachingOperationNameGenerator operationNames; + @Bean public Docket thingsboardApi() { TypeResolver typeResolver = new TypeResolver(); @@ -77,29 +113,110 @@ public class SwaggerConfiguration { typeResolver.resolve( String.class); - return new Docket(DocumentationType.SWAGGER_2) + return new Docket(DocumentationType.OAS_30) .groupName("thingsboard") .apiInfo(apiInfo()) - .alternateTypeRules( + .additionalModels( + typeResolver.resolve(ThingsboardErrorResponse.class), + typeResolver.resolve(LoginRequest.class), + typeResolver.resolve(LoginResponse.class) + ) + /* .alternateTypeRules( new AlternateTypeRule( jsonNodeType, - stringType)) + stringType))*/ .select() .paths(apiPaths()) + .paths(any()) .build() - .securitySchemes(newArrayList(jwtTokenKey())) + .globalResponses(HttpMethod.GET, + List.of( + new ResponseBuilder() + .code("401") + .description("Unauthorized") + .representation(MediaType.APPLICATION_JSON) + .apply(classRepresentation(ThingsboardErrorResponse.class, true)) + .build() + ) + ) + .securitySchemes(newArrayList(httpLogin())) .securityContexts(newArrayList(securityContext())) .enableUrlTemplating(true); } - private ApiKey jwtTokenKey() { - return new ApiKey("X-Authorization", "JWT token", "header"); + @Bean + @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER) + ApiListingScannerPlugin loginEndpointListingScanner() { + return new ApiListingScannerPlugin() { + @Override + public List apply(DocumentationContext context) { + return List.of(loginEndpointApiDescription()); + } + + @Override + public boolean supports(DocumentationType delimiter) { + return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter); + } + }; + } + + @Bean + @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER) + ApiListingBuilderPlugin loginEndpointListingBuilder() { + return new ApiListingBuilderPlugin() { + @Override + public void apply(ApiListingContext apiListingContext) { + if (apiListingContext.getResourceGroup().getGroupName().equals("default")) { + ApiListing apiListing = apiListingContext.apiListingBuilder().build(); + if (apiListing.getResourcePath().equals("/api/auth/login")) { + apiListingContext.apiListingBuilder().tags(Set.of(new Tag("login-endpoint", "Login Endpoint"))); + apiListingContext.apiListingBuilder().description("Login Endpoint"); + } + } + } + + @Override + public boolean supports(DocumentationType delimiter) { + return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter); + } + }; + } + + @Bean + UiConfiguration uiConfig() { + return UiConfigurationBuilder.builder() + .deepLinking(true) + .displayOperationId(false) + .defaultModelsExpandDepth(1) + .defaultModelExpandDepth(1) + .defaultModelRendering(ModelRendering.EXAMPLE) + .displayRequestDuration(false) + .docExpansion(DocExpansion.NONE) + .filter(false) + .maxDisplayedTags(null) + .operationsSorter(OperationsSorter.ALPHA) + .showExtensions(false) + .showCommonExtensions(false) + .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS) + .validatorUrl(null) + .syntaxHighlightActivate(true) + .syntaxHighlightTheme("agate") + .build(); + } + + private SecurityScheme httpLogin() { + return HttpLoginPasswordScheme + .X_AUTHORIZATION_BUILDER + .loginEndpoint("/api/auth/login") + .name("HTTP login form") + .description("Enter Username / Password") + .build(); } private SecurityContext securityContext() { return SecurityContext.builder() .securityReferences(defaultAuth()) - .forPaths(securityPaths()) + .operationSelector(securityPathOperationSelector()) .build(); } @@ -107,11 +224,8 @@ public class SwaggerConfiguration { return regex(apiPathRegex); } - private Predicate securityPaths() { - return and( - regex(securityPathRegex), - not(regex(nonSecurityPathRegex)) - ); + private Predicate securityPathOperationSelector() { + return new SecurityPathOperationSelector(securityPathRegex, nonSecurityPathRegex); } List defaultAuth() { @@ -120,7 +234,7 @@ public class SwaggerConfiguration { authorizationScopes[1] = new AuthorizationScope(Authority.TENANT_ADMIN.name(), "Tenant administrator"); authorizationScopes[2] = new AuthorizationScope(Authority.CUSTOMER_USER.name(), "Customer"); return newArrayList( - new SecurityReference("X-Authorization", authorizationScopes)); + new SecurityReference("HTTP login form", authorizationScopes)); } private ApiInfo apiInfo() { @@ -134,4 +248,75 @@ public class SwaggerConfiguration { .build(); } + private ApiDescription loginEndpointApiDescription() { + return new ApiDescription(null, "/api/auth/login", "Login method to get user JWT token data", "Login endpoint", Collections.singletonList( + new OperationBuilder(operationNames) + .summary("Login method to get user JWT token data") + .tags(Set.of("login-endpoint")) + .authorizations(new ArrayList<>()) + .position(0) + .codegenMethodNameStem("loginPost") + .method(HttpMethod.POST) + .notes("Login method to get user JWT token data.\n\nValue of the response **token** field can be used as JWT token value for authorization.") + .requestParameters( + List.of( + new RequestParameterBuilder() + .in(ParameterType.BODY) + .required(true) + .description("Login request") + .content(c -> + c.requestBody(true) + .representation(MediaType.APPLICATION_JSON) + .apply(classRepresentation(LoginRequest.class, false)) + ) + .build() + ) + ) + .responses(loginResponses()) + .build() + ), false); + } + + private Collection loginResponses() { + return List.of( + new ResponseBuilder() + .code("200") + .description("OK") + .representation(MediaType.APPLICATION_JSON) + .apply(classRepresentation(LoginResponse.class, true)). + build() + ); + } + + /** Helper methods **/ + + private Consumer classRepresentation(Class clazz, boolean isResponse) { + return r -> r.model( + m -> + m.referenceModel(ref -> + ref.key(k -> + k.qualifiedModelName(q -> + q.namespace(clazz.getPackageName()) + .name(clazz.getSimpleName())).isResponse(isResponse))) + ); + } + + private static class SecurityPathOperationSelector implements Predicate { + + private final Predicate securityPathSelector; + + SecurityPathOperationSelector(String securityPathRegex, String nonSecurityPathRegex) { + this.securityPathSelector = regex(securityPathRegex).and( + not( + regex(nonSecurityPathRegex) + )); + } + + @Override + public boolean test(OperationContext operationContext) { + return this.securityPathSelector.test(operationContext.requestMappingPattern()); + } + } + + } diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java index 2718b455b9..1a5b2f86fd 100644 --- a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java @@ -64,6 +64,7 @@ import java.util.List; public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapter { public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; + public static final String JWT_TOKEN_HEADER_PARAM_V2 = "Authorization"; public static final String JWT_TOKEN_QUERY_PARAM = "token"; public static final String WEBJARS_ENTRY_POINT = "/webjars/**"; diff --git a/application/src/main/java/org/thingsboard/server/config/WebConfig.java b/application/src/main/java/org/thingsboard/server/config/WebConfig.java index 500d1bd06e..e4a1eea01b 100644 --- a/application/src/main/java/org/thingsboard/server/config/WebConfig.java +++ b/application/src/main/java/org/thingsboard/server/config/WebConfig.java @@ -18,12 +18,20 @@ package org.thingsboard.server.config; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + @Controller public class WebConfig { - @RequestMapping(value = {"/assets", "/assets/", "/{path:^(?!api$)(?!assets$)(?!static$)(?!webjars$)[^\\.]*}/**"}) + @RequestMapping(value = {"/assets", "/assets/", "/{path:^(?!api$)(?!assets$)(?!static$)(?!webjars$)(?!swagger-ui$)[^\\.]*}/**"}) public String redirect() { return "forward:/index.html"; } + @RequestMapping("/swagger-ui.html") + public void redirectSwagger(HttpServletResponse response) throws IOException { + response.sendRedirect("/swagger-ui/"); + } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index 7c881e8b67..185f8ff526 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -44,6 +44,7 @@ public class ControllerConstants { protected static final String OTA_PACKAGE_ID_PARAM_DESCRIPTION = "A string value representing the ota package id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; protected static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String RULE_NODE_ID_PARAM_DESCRIPTION = "A string value representing the rule node id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String WIDGET_TYPE_ID_PARAM_DESCRIPTION = "A string value representing the widget type id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String RESOURCE_ID_PARAM_DESCRIPTION = "A string value representing the resource id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 8996367c36..bb27451349 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -95,6 +95,7 @@ import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_S import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TEXT_SEARCH_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TYPES_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TYPE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.RULE_NODE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; @@ -434,7 +435,7 @@ public class RuleChainController extends BaseController { @RequestMapping(value = "/ruleNode/{ruleNodeId}/debugIn", method = RequestMethod.GET) @ResponseBody public JsonNode getLatestRuleNodeDebugInput( - @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @ApiParam(value = RULE_NODE_ID_PARAM_DESCRIPTION) @PathVariable(RULE_NODE_ID) String strRuleNodeId) throws ThingsboardException { checkParameter(RULE_NODE_ID, strRuleNodeId); try { diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index a6cc14dce1..facee5d87f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -79,7 +79,7 @@ public class WidgetsBundleController extends BaseController { @ApiOperation(value = "Create Or Update Widget Bundle (saveWidgetsBundle)", notes = "Create or update the Widget Bundle. " + WIDGET_BUNDLE_DESCRIPTION + " " + - "When creating the bundle, platform generates Widget Bundle Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "When creating the bundle, platform generates Widget Bundle Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)). " + "The newly created Widget Bundle Id will be present in the response. " + "Specify existing Widget Bundle id to update the Widget Bundle. " + "Referencing non-existing Widget Bundle Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/extractor/JwtHeaderTokenExtractor.java b/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/extractor/JwtHeaderTokenExtractor.java index 7c9dd55c87..1f1200752f 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/extractor/JwtHeaderTokenExtractor.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/extractor/JwtHeaderTokenExtractor.java @@ -30,7 +30,10 @@ public class JwtHeaderTokenExtractor implements TokenExtractor { public String extract(HttpServletRequest request) { String header = request.getHeader(ThingsboardSecurityConfiguration.JWT_TOKEN_HEADER_PARAM); if (StringUtils.isBlank(header)) { - throw new AuthenticationServiceException("Authorization header cannot be blank!"); + header = request.getHeader(ThingsboardSecurityConfiguration.JWT_TOKEN_HEADER_PARAM_V2); + if (StringUtils.isBlank(header)) { + throw new AuthenticationServiceException("Authorization header cannot be blank!"); + } } if (header.length() < HEADER_PREFIX.length()) { diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginRequest.java b/application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginRequest.java index a90effdd36..f645b989d2 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginRequest.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginRequest.java @@ -17,9 +17,14 @@ package org.thingsboard.server.service.security.auth.rest; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +@ApiModel public class LoginRequest { + private String username; + private String password; @JsonCreator @@ -28,10 +33,12 @@ public class LoginRequest { this.password = password; } + @ApiModelProperty(position = 1, required = true, value = "User email", example = "tenant@thingsboard.org") public String getUsername() { return username; } + @ApiModelProperty(position = 2, required = true, value = "User password", example = "tenant") public String getPassword() { return password; } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginResponse.java b/application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginResponse.java new file mode 100644 index 0000000000..e39e0af14f --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginResponse.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2021 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.security.auth.rest; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel +@Data +public class LoginResponse { + + @ApiModelProperty(position = 1, required = true, value = "JWT token", + example = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIi...") + private String token; + + @ApiModelProperty(position = 2, required = true, value = "Refresh token", + example = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIi...") + private String refreshToken; + +} diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 6644e1b62e..b7867360aa 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -845,9 +845,9 @@ edges: persistToTelemetry: "${EDGES_PERSIST_STATE_TO_TELEMETRY:false}" swagger: - api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}" - security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api.*}" - non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/noauth.*}" + api_path_regex: "${SWAGGER_API_PATH_REGEX:/api/.*}" + security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api/.*}" + non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/(?:noauth|v1)/.*}" title: "${SWAGGER_TITLE:ThingsBoard REST API}" description: "${SWAGGER_DESCRIPTION:For instructions how to authorize requests please visit REST API documentation page.}" contact: diff --git a/pom.xml b/pom.xml index 0ca42294fa..cf419aa9b4 100755 --- a/pom.xml +++ b/pom.xml @@ -46,8 +46,8 @@ 2.4.3 3.3.0 0.7.0 - 1.7.7 - 1.2.3 + 1.7.32 + 1.2.6 0.10 4.10.0 4.0.5 @@ -83,9 +83,8 @@ 4.8.0 2.19.1 3.0.2 - 2.6.1 - 1.0.0 - 1.5.10 + 3.0.1 + 1.6.3 0.7 1.15.0 1.67 @@ -1620,8 +1619,8 @@ ${curator.version} - io.springfox - springfox-swagger2 + org.thingsboard + springfox-boot-starter ${springfox-swagger.version} @@ -1699,11 +1698,6 @@ fst ${fst.version} - - io.springfox.ui - springfox-swagger-ui-rfc6570 - ${springfox-swagger-ui-rfc6570.version} - org.locationtech.spatial4j spatial4j From 8d28a28b08bf9b16794345ccaa908f051d66716a Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Thu, 28 Oct 2021 18:08:17 +0300 Subject: [PATCH 187/303] Implement entities search within all tenants --- .../controller/EntityQueryController.java | 83 ++++++- .../data/search/EntitiesSearchRequest.java | 25 +++ .../data/search/EntitySearchResult.java | 50 +++++ .../service/query/EntitiesSearchService.java | 26 +++ .../query/EntitiesSearchServiceImpl.java | 208 ++++++++++++++++++ .../permission/PermissionChecker.java | 1 + .../permission/SysAdminPermissions.java | 31 +-- .../common/data/query/EntityFilterType.java | 3 +- .../data/query/EntityNameOrIdFilter.java | 32 +++ .../query/DefaultEntityQueryRepository.java | 52 ++++- .../dao/sql/query/EntityKeyMapping.java | 60 ++++- 11 files changed, 532 insertions(+), 39 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java create mode 100644 application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java create mode 100644 application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 019066c636..e5467c8ae9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -17,9 +17,10 @@ package org.thingsboard.server.controller; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -36,20 +37,30 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; +import org.thingsboard.server.data.search.EntitiesSearchRequest; +import org.thingsboard.server.data.search.EntitySearchResult; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.query.EntitiesSearchService; import org.thingsboard.server.service.query.EntityQueryService; import static org.thingsboard.server.controller.ControllerConstants.ALARM_DATA_QUERY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_COUNT_QUERY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_DATA_QUERY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; @RestController @TbCoreComponent @RequestMapping("/api") +@RequiredArgsConstructor public class EntityQueryController extends BaseController { - @Autowired - private EntityQueryService entityQueryService; + private final EntityQueryService entityQueryService; + private final EntitiesSearchService entitiesSearchService; private static final int MAX_PAGE_SIZE = 100; @@ -123,4 +134,70 @@ public class EntityQueryController extends BaseController { } } + @ApiOperation(value = "Search entities (searchEntities)", notes = "Search entities with specified entity type by id or name within the whole platform. " + + "Searchable entity types are: CUSTOMER, USER, DEVICE, DEVICE_PROFILE, ASSET, ENTITY_VIEW, DASHBOARD, " + + "RULE_CHAIN, EDGE, OTA_PACKAGE, TB_RESOURCE, WIDGETS_BUNDLE, TENANT, TENANT_PROFILE." + NEW_LINE + + "The platform will search for entities, where a name contains the search text (case-insensitively), " + + "or if the search query is a valid UUID (e.g. 128e4d40-26b3-11ec-aaeb-c7661c54701e) then " + + "it will also search for an entity where id fully matches the query. If search query is empty " + + "then all entities will be returned (according to page number, page size and sorting)." + NEW_LINE + + "The returned result is a page of EntitySearchResult, which contains: " + + "entity id, entity fields represented as strings, tenant info and owner info. " + + "Returned entity fields are: name, type (will be present for USER, DEVICE, ASSET, ENTITY_VIEW, RULE_CHAIN, " + + "EDGE, OTA_PACKAGE, TB_RESOURCE entity types; in case of USER - the type is its authority), " + + "createdTime and lastActivityTime (will only be present for DEVICE and USER; for USER it is its last login time). " + + "Tenant info contains tenant's id and title; owner info contains the same info for an entity's owner " + + "(its customer, or if it is not a customer's entity - tenant)." + NEW_LINE + + "Example response value:\n" + + "{\n" + + " \"data\": [\n" + + " {\n" + + " \"entityId\": {\n" + + " \"entityType\": \"DEVICE\",\n" + + " \"id\": \"48be0670-25c9-11ec-a618-8165eb6b112a\"\n" + + " },\n" + + " \"fields\": {\n" + + " \"name\": \"Thermostat T1\",\n" + + " \"createdTime\": \"1633430698071\",\n" + + " \"lastActivityTime\": \"1635761085285\",\n" + + " \"type\": \"thermostat\"\n" + + " },\n" + + " \"tenantInfo\": {\n" + + " \"id\": {\n" + + " \"entityType\": \"TENANT\",\n" + + " \"id\": \"2ddd6120-25c9-11ec-a618-8165eb6b112a\"\n" + + " },\n" + + " \"name\": \"Tenant\"\n" + + " },\n" + + " \"ownerInfo\": {\n" + + " \"id\": {\n" + + " \"entityType\": \"CUSTOMER\",\n" + + " \"id\": \"26cba800-eee3-11eb-9e2c-fb031bd4619c\"\n" + + " },\n" + + " \"name\": \"Customer A\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"totalPages\": 1,\n" + + " \"totalElements\": 1,\n" + + " \"hasNext\": false\n" + + "}") + @PostMapping("/entities/search") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") + public PageData searchEntities(@RequestBody EntitiesSearchRequest request, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "name, type, createdTime, lastActivityTime, createdTime, tenantId, customerId", required = false) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES, required = false) + @RequestParam(required = false) String sortOrder) throws ThingsboardException { + try { + return entitiesSearchService.searchEntities(getCurrentUser(), request, createPageLink(pageSize, page, null, sortProperty, sortOrder)); + } catch (Exception e) { + throw handleException(e); + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java b/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java new file mode 100644 index 0000000000..48f8966107 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2021 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.data.search; + +import lombok.Data; +import org.thingsboard.server.common.data.EntityType; + +@Data +public class EntitiesSearchRequest { + private EntityType entityType; + private String searchQuery; +} diff --git a/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java b/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java new file mode 100644 index 0000000000..a26d580b7d --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java @@ -0,0 +1,50 @@ +/** + * Copyright © 2016-2021 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.data.search; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.Map; + +@Data +public class EntitySearchResult { + private EntityId entityId; + private Map fields; + + private EntityTenantInfo tenantInfo; + private EntityOwnerInfo ownerInfo; + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static final class EntityTenantInfo { + private TenantId id; + private String name; + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static final class EntityOwnerInfo { + private EntityId id; + private String name; + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java b/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java new file mode 100644 index 0000000000..36a34f89e7 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2021 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.query; + +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.data.search.EntitiesSearchRequest; +import org.thingsboard.server.data.search.EntitySearchResult; +import org.thingsboard.server.service.security.model.SecurityUser; + +public interface EntitiesSearchService { + PageData searchEntities(SecurityUser user, EntitiesSearchRequest request, PageLink pageLink); +} diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java new file mode 100644 index 0000000000..1753a49c0d --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java @@ -0,0 +1,208 @@ +/** + * Copyright © 2016-2021 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.query; + +import com.google.common.base.Strings; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.ContactBased; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.SortOrder; +import org.thingsboard.server.common.data.query.EntityData; +import org.thingsboard.server.common.data.query.EntityDataPageLink; +import org.thingsboard.server.common.data.query.EntityDataQuery; +import org.thingsboard.server.common.data.query.EntityDataSortOrder; +import org.thingsboard.server.common.data.query.EntityKey; +import org.thingsboard.server.common.data.query.EntityKeyType; +import org.thingsboard.server.common.data.query.EntityNameOrIdFilter; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.data.search.EntitiesSearchRequest; +import org.thingsboard.server.data.search.EntitySearchResult; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.model.SecurityUser; +import org.thingsboard.server.service.state.DefaultDeviceStateService; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.thingsboard.server.common.data.EntityType.ASSET; +import static org.thingsboard.server.common.data.EntityType.CUSTOMER; +import static org.thingsboard.server.common.data.EntityType.DASHBOARD; +import static org.thingsboard.server.common.data.EntityType.DEVICE; +import static org.thingsboard.server.common.data.EntityType.DEVICE_PROFILE; +import static org.thingsboard.server.common.data.EntityType.EDGE; +import static org.thingsboard.server.common.data.EntityType.ENTITY_VIEW; +import static org.thingsboard.server.common.data.EntityType.OTA_PACKAGE; +import static org.thingsboard.server.common.data.EntityType.RULE_CHAIN; +import static org.thingsboard.server.common.data.EntityType.TB_RESOURCE; +import static org.thingsboard.server.common.data.EntityType.TENANT; +import static org.thingsboard.server.common.data.EntityType.TENANT_PROFILE; +import static org.thingsboard.server.common.data.EntityType.USER; +import static org.thingsboard.server.common.data.EntityType.WIDGETS_BUNDLE; +import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.CREATED_TIME; +import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.CUSTOMER_ID; +import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.LAST_ACTIVITY_TIME; +import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.NAME; +import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.TENANT_ID; +import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.TYPE; + +@Service +@TbCoreComponent +@RequiredArgsConstructor +@Slf4j +public class EntitiesSearchServiceImpl implements EntitiesSearchService { + private final EntityQueryService entityQueryService; + + private final TenantService tenantService; + private final CustomerService customerService; + private final DefaultDeviceStateService deviceStateService; + + private static final List entityResponseFields = Stream.of(CREATED_TIME, NAME, TYPE, TENANT_ID, CUSTOMER_ID) + .map(field -> new EntityKey(EntityKeyType.ENTITY_FIELD, field)) + .collect(Collectors.toList()); + + private static final Set searchableEntityTypes = EnumSet.of( + TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, RULE_CHAIN, ENTITY_VIEW, + WIDGETS_BUNDLE, TENANT_PROFILE, DEVICE_PROFILE, TB_RESOURCE, OTA_PACKAGE, EDGE + ); + + @Override + public PageData searchEntities(SecurityUser user, EntitiesSearchRequest request, PageLink pageLink) { + EntityType entityType = request.getEntityType(); + if (!searchableEntityTypes.contains(entityType)) { + return new PageData<>(); + } + + EntityDataQuery query = createSearchQuery(request.getSearchQuery(), entityType, pageLink); + PageData resultPage = entityQueryService.findEntityDataByQuery(user, query); + + Map> localOwnersCache = new HashMap<>(); + return resultPage.mapData(entityData -> { + Map fields = new HashMap<>(); + entityData.getLatest().values().stream() + .flatMap(values -> values.entrySet().stream()) + .forEach(entry -> fields.put(entry.getKey(), Strings.emptyToNull(entry.getValue().getValue()))); + + EntitySearchResult entitySearchResult = new EntitySearchResult(); + + entitySearchResult.setEntityId(entityData.getEntityId()); + entitySearchResult.setFields(fields); + setOwnerInfo(entitySearchResult, localOwnersCache); + + return entitySearchResult; + }); + } + + private EntityDataQuery createSearchQuery(String searchQuery, EntityType entityType, PageLink pageLink) { + EntityDataPageLink entityDataPageLink = new EntityDataPageLink(); + entityDataPageLink.setPageSize(pageLink.getPageSize()); + entityDataPageLink.setPage(pageLink.getPage()); + if (pageLink.getSortOrder() != null && StringUtils.isNotEmpty(pageLink.getSortOrder().getProperty())) { + entityDataPageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, pageLink.getSortOrder().getProperty()), + EntityDataSortOrder.Direction.valueOf(Optional.ofNullable(pageLink.getSortOrder().getDirection()).orElse(SortOrder.Direction.ASC).name()))); + } + + EntityNameOrIdFilter filter = new EntityNameOrIdFilter(); + filter.setEntityType(entityType); + filter.setNameOrId(searchQuery); + + List entityFields = entityResponseFields; + List latestValues = Collections.emptyList(); + + if (entityType == USER) { + entityFields = new ArrayList<>(entityFields); + entityFields.add(new EntityKey(EntityKeyType.ENTITY_FIELD, LAST_ACTIVITY_TIME)); + } else if (entityType == DEVICE) { + EntityKey lastActivityTimeKey; + if (deviceStateService.isPersistToTelemetry()) { + lastActivityTimeKey = new EntityKey(EntityKeyType.TIME_SERIES, LAST_ACTIVITY_TIME); + } else { + lastActivityTimeKey = new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, LAST_ACTIVITY_TIME); + } + latestValues = List.of(lastActivityTimeKey); + if (entityDataPageLink.getSortOrder() != null && entityDataPageLink.getSortOrder().getKey().getKey().equals(LAST_ACTIVITY_TIME)) { + entityDataPageLink.getSortOrder().setKey(lastActivityTimeKey); + } + } + + return new EntityDataQuery(filter, entityDataPageLink, entityFields, latestValues, Collections.emptyList()); + } + + private void setOwnerInfo(EntitySearchResult entitySearchResult, Map> localOwnersCache) { + Map fields = entitySearchResult.getFields(); + + UUID tenantUuid = toUuid(fields.remove(TENANT_ID)); + UUID customerUuid = toUuid(fields.remove(CUSTOMER_ID)); + + Tenant tenant = null; + if (tenantUuid != null) { + tenant = getTenant(new TenantId(tenantUuid), localOwnersCache); + } + + ContactBased owner; + if (customerUuid != null) { + owner = getCustomer(new CustomerId(customerUuid), localOwnersCache); + } else { + owner = tenant; + } + + if (tenant != null) { + entitySearchResult.setTenantInfo(new EntitySearchResult.EntityTenantInfo(tenant.getId(), tenant.getName())); + } + if (owner != null) { + entitySearchResult.setOwnerInfo(new EntitySearchResult.EntityOwnerInfo(owner.getId(), owner.getName())); + } + } + + private Tenant getTenant(TenantId tenantId, Map> localOwnersCache) { + return (Tenant) localOwnersCache.computeIfAbsent(tenantId, id -> tenantService.findTenantById(tenantId)); + } + + private Customer getCustomer(CustomerId customerId, Map> localOwnersCache) { + return (Customer) localOwnersCache.computeIfAbsent(customerId, id -> customerService.findCustomerById(TenantId.SYS_TENANT_ID, customerId)); + } + + private UUID toUuid(String uuid) { + try { + UUID id = UUID.fromString(uuid); + if (!id.equals(EntityId.NULL_UUID)) { + return id; + } + } catch (Exception ignored) {} + + return null; + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java b/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java index 3f6e16d753..45a43876e6 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java @@ -69,5 +69,6 @@ public interface PermissionChecker { } }; + PermissionChecker allowReadPermissionChecker = new GenericPermissionChecker(Operation.READ, Operation.READ_TELEMETRY, Operation.READ_ATTRIBUTES); } diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java index f703102e18..8f9648dc93 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java @@ -17,10 +17,7 @@ package org.thingsboard.server.service.security.permission; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.HasTenantId; -import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.service.security.model.SecurityUser; @Component(value="sysAdminPermissions") @@ -29,23 +26,29 @@ public class SysAdminPermissions extends AbstractPermissions { public SysAdminPermissions() { super(); put(Resource.ADMIN_SETTINGS, PermissionChecker.allowAllPermissionChecker); - put(Resource.DASHBOARD, new PermissionChecker.GenericPermissionChecker(Operation.READ)); + put(Resource.DASHBOARD, PermissionChecker.allowReadPermissionChecker); put(Resource.TENANT, PermissionChecker.allowAllPermissionChecker); - put(Resource.RULE_CHAIN, systemEntityPermissionChecker); - put(Resource.USER, userPermissionChecker); + put(Resource.RULE_CHAIN, PermissionChecker.allowReadPermissionChecker); + put(Resource.USER, PermissionChecker.allowAllPermissionChecker); put(Resource.WIDGETS_BUNDLE, systemEntityPermissionChecker); put(Resource.WIDGET_TYPE, systemEntityPermissionChecker); put(Resource.OAUTH2_CONFIGURATION_INFO, PermissionChecker.allowAllPermissionChecker); put(Resource.OAUTH2_CONFIGURATION_TEMPLATE, PermissionChecker.allowAllPermissionChecker); put(Resource.TENANT_PROFILE, PermissionChecker.allowAllPermissionChecker); - put(Resource.TB_RESOURCE, systemEntityPermissionChecker); + put(Resource.TB_RESOURCE, PermissionChecker.allowAllPermissionChecker); + put(Resource.CUSTOMER, PermissionChecker.allowReadPermissionChecker); + put(Resource.ASSET, PermissionChecker.allowReadPermissionChecker); + put(Resource.DEVICE, PermissionChecker.allowReadPermissionChecker); + put(Resource.ENTITY_VIEW, PermissionChecker.allowReadPermissionChecker); + put(Resource.DEVICE_PROFILE, PermissionChecker.allowReadPermissionChecker); + put(Resource.OTA_PACKAGE, PermissionChecker.allowReadPermissionChecker); + put(Resource.EDGE, PermissionChecker.allowReadPermissionChecker); } private static final PermissionChecker systemEntityPermissionChecker = new PermissionChecker() { @Override public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { - if (entity.getTenantId() != null && !entity.getTenantId().isNullUid()) { return false; } @@ -53,16 +56,4 @@ public class SysAdminPermissions extends AbstractPermissions { } }; - private static final PermissionChecker userPermissionChecker = new PermissionChecker() { - - @Override - public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) { - if (Authority.CUSTOMER_USER.equals(userEntity.getAuthority())) { - return false; - } - return true; - } - - }; - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java index 1a843c7b0f..c75d6bf4df 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java @@ -29,7 +29,8 @@ public enum EntityFilterType { DEVICE_SEARCH_QUERY("deviceSearchQuery"), ENTITY_VIEW_SEARCH_QUERY("entityViewSearchQuery"), EDGE_SEARCH_QUERY("edgeSearchQuery"), - API_USAGE_STATE("apiUsageState"); + API_USAGE_STATE("apiUsageState"), + ENTITY_NAME_OR_ID("entityNameOrId"); private final String label; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java new file mode 100644 index 0000000000..1fcb9e9350 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.query; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.thingsboard.server.common.data.EntityType; + +@EqualsAndHashCode(callSuper = true) +@Data +public class EntityNameOrIdFilter extends EntitySearchQueryFilter { + private String nameOrId; + private EntityType entityType; + + @Override + public EntityFilterType getType() { + return EntityFilterType.ENTITY_NAME_OR_ID; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index 4b331f78f2..cbecc96f59 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.query.EntityFilterType; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.EntityListFilter; import org.thingsboard.server.common.data.query.EntityNameFilter; +import org.thingsboard.server.common.data.query.EntityNameOrIdFilter; import org.thingsboard.server.common.data.query.EntitySearchQueryFilter; import org.thingsboard.server.common.data.query.EntityTypeFilter; import org.thingsboard.server.common.data.query.EntityViewSearchQueryFilter; @@ -236,6 +237,12 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { entityTableMap.put(EntityType.TENANT, "tenant"); entityTableMap.put(EntityType.API_USAGE_STATE, SELECT_API_USAGE_STATE); entityTableMap.put(EntityType.EDGE, "edge"); + entityTableMap.put(EntityType.RULE_CHAIN, "rule_chain"); + entityTableMap.put(EntityType.WIDGETS_BUNDLE, "widgets_bundle"); + entityTableMap.put(EntityType.TENANT_PROFILE, "tenant_profile"); + entityTableMap.put(EntityType.DEVICE_PROFILE, "device_profile"); + entityTableMap.put(EntityType.TB_RESOURCE, "resource"); + entityTableMap.put(EntityType.OTA_PACKAGE, "ota_package"); } public static EntityType[] RELATION_QUERY_ENTITY_TYPES = new EntityType[]{ @@ -441,7 +448,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { Optional sortOrderMappingOpt = mappings.stream().filter(EntityKeyMapping::isSortOrder).findFirst(); if (sortOrderMappingOpt.isPresent()) { EntityKeyMapping sortOrderMapping = sortOrderMappingOpt.get(); - String direction = sortOrder.getDirection() == EntityDataSortOrder.Direction.ASC ? "asc" : "desc"; + String direction = sortOrder.getDirection() == EntityDataSortOrder.Direction.ASC ? "asc" : "desc nulls last"; if (sortOrderMapping.getEntityKey().getType() == EntityKeyType.ENTITY_FIELD) { dataQuery = String.format("%s order by %s %s, result.id %s", dataQuery, sortOrderMapping.getValueAlias(), direction, direction); } else { @@ -471,15 +478,26 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType()); String result = permissionQuery; if (!entityFilterQuery.isEmpty()) { - result += " and (" + entityFilterQuery + ")"; + if (!result.isEmpty()) { + result += " and (" + entityFilterQuery + ")"; + } else { + result = "(" + entityFilterQuery + ")"; + } } if (!entityFieldsQuery.isEmpty()) { - result += " and (" + entityFieldsQuery + ")"; + if (!result.isEmpty()) { + result += " and (" + entityFieldsQuery + ")"; + } else { + result = "(" + entityFieldsQuery + ")"; + } } return result; } private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter) { + if (ctx.getTenantId().equals(TenantId.SYS_TENANT_ID)) { + return ""; + } switch (entityFilter.getType()) { case RELATIONS_QUERY: case DEVICE_SEARCH_QUERY: @@ -548,6 +566,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { case API_USAGE_STATE: case ENTITY_TYPE: return ""; + case ENTITY_NAME_OR_ID: + return entityNameOrIdQuery(ctx, (EntityNameOrIdFilter) entityFilter); default: throw new RuntimeException("Not implemented!"); } @@ -759,7 +779,27 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private String entityNameQuery(QueryContext ctx, EntityNameFilter filter) { ctx.addStringParameter("entity_filter_name_filter", filter.getEntityNameFilter()); - return "lower(e.search_text) like lower(concat(:entity_filter_name_filter, '%%'))"; + return "lower(e.search_text) like lower(concat('%', :entity_filter_name_filter, '%'))"; + } + + private String entityNameOrIdQuery(QueryContext ctx, EntityNameOrIdFilter filter) { + String nameOrId = filter.getNameOrId(); + if (StringUtils.isNotEmpty(nameOrId)) { + nameOrId = nameOrId.replaceAll("%", "\\\\%").replaceAll("_", "\\\\_"); + ctx.addStringParameter("entity_id_or_search_text_filter", nameOrId); + String query = ""; + + String searchTextField = EntityKeyMapping.searchTextFields.get(filter.getEntityType()); + query += "lower(e." + searchTextField + ") like lower(concat('%', :entity_id_or_search_text_filter, '%'))"; + + try { + UUID.fromString(nameOrId); + query += " or e.id = :entity_id_or_search_text_filter::uuid"; + } catch (Exception ignored) {} + + return query; + } + return "true"; } private String typeQuery(QueryContext ctx, EntityFilter filter) { @@ -787,7 +827,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { } ctx.addStringParameter("entity_filter_type_query_type", type); ctx.addStringParameter("entity_filter_type_query_name", name); - return "e.type = :entity_filter_type_query_type and lower(e.search_text) like lower(concat(:entity_filter_type_query_name, '%%'))"; + return "e.type = :entity_filter_type_query_type and lower(e.search_text) like lower(concat('%', :entity_filter_type_query_name, '%'))"; } private EntityType resolveEntityType(EntityFilter entityFilter) { @@ -816,6 +856,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { return ((RelationsQueryFilter) entityFilter).getRootEntity().getEntityType(); case API_USAGE_STATE: return EntityType.API_USAGE_STATE; + case ENTITY_NAME_OR_ID: + return ((EntityNameOrIdFilter) entityFilter).getEntityType(); default: throw new RuntimeException("Not implemented!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index caed48758a..3d40156329 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -38,6 +38,7 @@ import org.thingsboard.server.dao.model.ModelConstants; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -53,6 +54,8 @@ public class EntityKeyMapping { private static final Map> allowedEntityFieldMap = new HashMap<>(); private static final Map entityFieldColumnMap = new HashMap<>(); private static final Map> aliases = new HashMap<>(); + private static final Map> propertiesFunctions = new EnumMap<>(EntityType.class); + public static final Map searchTextFields = new EnumMap<>(EntityType.class); public static final String CREATED_TIME = "createdTime"; public static final String ENTITY_TYPE = "entityType"; @@ -72,35 +75,51 @@ public class EntityKeyMapping { public static final String ZIP = "zip"; public static final String PHONE = "phone"; public static final String ADDITIONAL_INFO = "additionalInfo"; + public static final String TENANT_ID = "tenantId"; + public static final String CUSTOMER_ID = "customerId"; + public static final String AUTHORITY = "authority"; + public static final String RESOURCE_TYPE = "resourceType"; + public static final String LAST_ACTIVITY_TIME = "lastActivityTime"; - public static final List typedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, ADDITIONAL_INFO); - public static final List widgetEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME); + public static final List typedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, ADDITIONAL_INFO, TENANT_ID); public static final List commonEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, ADDITIONAL_INFO); - public static final List dashboardEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE); - public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO); + + public static final List dashboardEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE, TENANT_ID); + public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO, TENANT_ID, CUSTOMER_ID); public static final List contactBasedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, EMAIL, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO); - public static final Set apiUsageStateEntityFields = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME)); + public static final Set apiUsageStateEntityFields = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME)); public static final Set commonEntityFieldsSet = new HashSet<>(commonEntityFields); public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO)); static { allowedEntityFieldMap.put(EntityType.DEVICE, new HashSet<>(labeledEntityFields)); allowedEntityFieldMap.put(EntityType.ASSET, new HashSet<>(labeledEntityFields)); + allowedEntityFieldMap.put(EntityType.EDGE, new HashSet<>(labeledEntityFields)); allowedEntityFieldMap.put(EntityType.ENTITY_VIEW, new HashSet<>(typedEntityFields)); + allowedEntityFieldMap.get(EntityType.ENTITY_VIEW).add(CUSTOMER_ID); allowedEntityFieldMap.put(EntityType.TENANT, new HashSet<>(contactBasedEntityFields)); allowedEntityFieldMap.get(EntityType.TENANT).add(REGION); allowedEntityFieldMap.put(EntityType.CUSTOMER, new HashSet<>(contactBasedEntityFields)); + allowedEntityFieldMap.get(EntityType.CUSTOMER).add(TENANT_ID); + + allowedEntityFieldMap.put(EntityType.USER, new HashSet<>(Arrays.asList(CREATED_TIME, FIRST_NAME, LAST_NAME, EMAIL, + ADDITIONAL_INFO, AUTHORITY, TENANT_ID, CUSTOMER_ID))); - allowedEntityFieldMap.put(EntityType.USER, new HashSet<>(Arrays.asList(CREATED_TIME, FIRST_NAME, LAST_NAME, EMAIL, ADDITIONAL_INFO))); + allowedEntityFieldMap.put(EntityType.DEVICE_PROFILE, new HashSet<>(commonEntityFields)); + allowedEntityFieldMap.get(EntityType.DEVICE_PROFILE).add(TENANT_ID); allowedEntityFieldMap.put(EntityType.DASHBOARD, new HashSet<>(dashboardEntityFields)); allowedEntityFieldMap.put(EntityType.RULE_CHAIN, new HashSet<>(commonEntityFields)); + allowedEntityFieldMap.get(EntityType.RULE_CHAIN).add(TENANT_ID); + allowedEntityFieldMap.get(EntityType.RULE_CHAIN).add(TYPE); allowedEntityFieldMap.put(EntityType.RULE_NODE, new HashSet<>(commonEntityFields)); - allowedEntityFieldMap.put(EntityType.WIDGET_TYPE, new HashSet<>(widgetEntityFields)); - allowedEntityFieldMap.put(EntityType.WIDGETS_BUNDLE, new HashSet<>(widgetEntityFields)); + allowedEntityFieldMap.put(EntityType.WIDGET_TYPE, new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TENANT_ID))); + allowedEntityFieldMap.put(EntityType.WIDGETS_BUNDLE, new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE, TENANT_ID))); allowedEntityFieldMap.put(EntityType.API_USAGE_STATE, apiUsageStateEntityFields); + allowedEntityFieldMap.put(EntityType.TB_RESOURCE, Set.of(CREATED_TIME, ENTITY_TYPE, RESOURCE_TYPE, TITLE, TENANT_ID)); + allowedEntityFieldMap.put(EntityType.OTA_PACKAGE, Set.of(CREATED_TIME, ENTITY_TYPE, TYPE, TITLE, TENANT_ID)); entityFieldColumnMap.put(CREATED_TIME, ModelConstants.CREATED_TIME_PROPERTY); entityFieldColumnMap.put(ENTITY_TYPE, ModelConstants.ENTITY_TYPE_PROPERTY); @@ -120,25 +139,42 @@ public class EntityKeyMapping { entityFieldColumnMap.put(ZIP, ModelConstants.ZIP_PROPERTY); entityFieldColumnMap.put(PHONE, ModelConstants.PHONE_PROPERTY); entityFieldColumnMap.put(ADDITIONAL_INFO, ModelConstants.ADDITIONAL_INFO_PROPERTY); + entityFieldColumnMap.put(TENANT_ID, ModelConstants.TENANT_ID_PROPERTY); + entityFieldColumnMap.put(CUSTOMER_ID, ModelConstants.CUSTOMER_ID_PROPERTY); + entityFieldColumnMap.put(AUTHORITY, ModelConstants.USER_AUTHORITY_PROPERTY); + entityFieldColumnMap.put(RESOURCE_TYPE, ModelConstants.RESOURCE_TYPE_COLUMN); Map contactBasedAliases = new HashMap<>(); contactBasedAliases.put(NAME, TITLE); contactBasedAliases.put(LABEL, TITLE); aliases.put(EntityType.TENANT, contactBasedAliases); - aliases.put(EntityType.CUSTOMER, contactBasedAliases); + aliases.put(EntityType.CUSTOMER, new HashMap<>(contactBasedAliases)); aliases.put(EntityType.DASHBOARD, contactBasedAliases); Map commonEntityAliases = new HashMap<>(); commonEntityAliases.put(TITLE, NAME); aliases.put(EntityType.DEVICE, commonEntityAliases); aliases.put(EntityType.ASSET, commonEntityAliases); aliases.put(EntityType.ENTITY_VIEW, commonEntityAliases); - aliases.put(EntityType.WIDGETS_BUNDLE, commonEntityAliases); + aliases.put(EntityType.EDGE, commonEntityAliases); + aliases.put(EntityType.WIDGETS_BUNDLE, new HashMap<>(commonEntityAliases)); + aliases.get(EntityType.WIDGETS_BUNDLE).put(NAME, TITLE); Map userEntityAliases = new HashMap<>(); userEntityAliases.put(TITLE, EMAIL); userEntityAliases.put(LABEL, EMAIL); userEntityAliases.put(NAME, EMAIL); + userEntityAliases.put(TYPE, AUTHORITY); aliases.put(EntityType.USER, userEntityAliases); + aliases.put(EntityType.TB_RESOURCE, Map.of(NAME, TITLE, TYPE, RESOURCE_TYPE)); + aliases.put(EntityType.OTA_PACKAGE, Map.of(NAME, TITLE)); + + propertiesFunctions.put(EntityType.USER, Map.of( + LAST_ACTIVITY_TIME, "cast(e.additional_info::json ->> 'lastLoginTs' as bigint)" + )); + + Arrays.stream(EntityType.values()).forEach(entityType -> { + searchTextFields.put(entityType, ModelConstants.SEARCH_TEXT_PROPERTY); + }); } private int index; @@ -179,6 +215,10 @@ public class EntityKeyMapping { String column = entityFieldColumnMap.get(alias); return String.format("cast(e.%s as varchar) as %s", column, getValueAlias()); } else { + Map entityPropertiesFunctions = propertiesFunctions.get(entityType); + if (entityPropertiesFunctions != null && entityPropertiesFunctions.containsKey(alias)) { + return String.format("%s as %s", entityPropertiesFunctions.get(alias), getValueAlias()); + } return String.format("'' as %s", getValueAlias()); } } From af2a5c241dddc49bde8c22f58496917157491c7f Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 2 Nov 2021 16:58:21 +0200 Subject: [PATCH 188/303] added CoAP Efento responses callback --- .../coap/callback/CoapEfentoCallback.java | 52 +++++++++++++++++++ .../efento/CoapEfentoTransportResource.java | 10 +++- 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapEfentoCallback.java diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapEfentoCallback.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapEfentoCallback.java new file mode 100644 index 0000000000..f2387bf0d1 --- /dev/null +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapEfentoCallback.java @@ -0,0 +1,52 @@ +/** + * Copyright © 2016-2021 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.transport.coap.callback; + +import org.eclipse.californium.core.coap.CoAP; +import org.eclipse.californium.core.coap.Response; +import org.eclipse.californium.core.server.resources.CoapExchange; +import org.thingsboard.server.common.transport.TransportServiceCallback; + +public class CoapEfentoCallback implements TransportServiceCallback { + + protected final CoapExchange exchange; + protected final CoAP.ResponseCode onSuccessResponse; + protected final CoAP.ResponseCode onFailureResponse; + + public CoapEfentoCallback(CoapExchange exchange, CoAP.ResponseCode onSuccessResponse, CoAP.ResponseCode onFailureResponse) { + this.exchange = exchange; + this.onSuccessResponse = onSuccessResponse; + this.onFailureResponse = onFailureResponse; + } + + @Override + public void onSuccess(Void msg) { + if (isConRequest()) { + Response response = new Response(onSuccessResponse); + response.setAcknowledged(true); + exchange.respond(response); + } + } + + @Override + public void onError(Throwable e) { + exchange.respond(onFailureResponse); + } + + protected boolean isConRequest() { + return exchange.advanced().getRequest().isConfirmable(); + } +} diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java index 59482d9fc2..06395109d1 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java @@ -21,6 +21,7 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.Request; +import org.eclipse.californium.core.coap.Response; import org.eclipse.californium.core.network.Exchange; import org.eclipse.californium.core.server.resources.CoapExchange; import org.eclipse.californium.core.server.resources.Resource; @@ -38,6 +39,7 @@ import org.thingsboard.server.gen.transport.coap.MeasurementsProtos; import org.thingsboard.server.transport.coap.AbstractCoapTransportResource; import org.thingsboard.server.transport.coap.CoapTransportContext; import org.thingsboard.server.transport.coap.callback.CoapDeviceAuthCallback; +import org.thingsboard.server.transport.coap.callback.CoapEfentoCallback; import org.thingsboard.server.transport.coap.callback.CoapOkCallback; import org.thingsboard.server.transport.coap.efento.utils.CoapEfentoUtils; @@ -97,7 +99,11 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { break; case DEVICE_INFO: case CONFIGURATION: - exchange.respond(CoAP.ResponseCode.CREATED); + Response response = new Response(CoAP.ResponseCode.CREATED); + if (exchange.advanced().getRequest().isConfirmable()) { + response.setAcknowledged(true); + exchange.respond(response); + } break; default: exchange.respond(CoAP.ResponseCode.BAD_REQUEST); @@ -120,7 +126,7 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { List efentoMeasurements = getEfentoMeasurements(protoMeasurements, sessionId); transportService.process(sessionInfo, transportContext.getEfentoCoapAdaptor().convertToPostTelemetry(sessionId, efentoMeasurements), - new CoapOkCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); + new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); reportSubscriptionInfo(sessionInfo, false, false); } catch (AdaptorException e) { log.error("[{}] Failed to decode Efento ProtoMeasurements: ", sessionId, e); From 4e1e8ce56b0d0f28d222eb662839b9a5ce6eeeac Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Tue, 2 Nov 2021 17:03:44 +0200 Subject: [PATCH 189/303] Added widget toastTargetId to the widgetContext --- .../src/app/modules/home/components/widget/widget.component.ts | 1 + ui-ngx/src/app/modules/home/models/widget-component.models.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 920f6721b9..f67a4b03de 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -279,6 +279,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI this.widgetContext.servicesMap = ServicesMap; this.widgetContext.isEdit = this.isEdit; this.widgetContext.isMobile = this.isMobile; + this.widgetContext.toastTargetId = this.toastTargetId; this.widgetContext.subscriptionApi = { createSubscription: this.createSubscription.bind(this), diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 59476df889..2a530c8b4e 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -230,6 +230,7 @@ export class WidgetContext { $scope: IDynamicWidgetComponent; isEdit: boolean; isMobile: boolean; + toastTargetId: string; widgetNamespace?: string; subscriptionApi?: WidgetSubscriptionApi; From aaead618aa22ec07d9c1f77d0484f628315d4559 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 3 Nov 2021 11:49:16 +0200 Subject: [PATCH 190/303] Set serialVersionUID for DeviceProfile class --- .../java/org/thingsboard/server/common/data/DeviceProfile.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 5e0419cf90..645e4892fc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -42,6 +42,8 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn @Slf4j public class DeviceProfile extends SearchTextBased implements HasName, HasTenantId, HasOtaPackage { + private static final long serialVersionUID = 6998485460273302018L; + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id that owns the profile.", readOnly = true) private TenantId tenantId; @NoXss From 34d6dc50b5e876c01400cd82bd653fb537e9f537 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Nov 2021 15:03:56 +0200 Subject: [PATCH 191/303] Swagger improvements --- .../server/config/SwaggerConfiguration.java | 132 +++++++++++++----- ...ThingsboardCredentialsExpiredResponse.java | 4 + .../exception/ThingsboardErrorResponse.java | 20 +++ pom.xml | 2 +- 4 files changed, 124 insertions(+), 34 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java index ba3771616a..25cc862924 100644 --- a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java @@ -15,25 +15,30 @@ */ package org.thingsboard.server.config; -import com.fasterxml.classmate.ResolvedType; import com.fasterxml.classmate.TypeResolver; -import com.fasterxml.jackson.databind.JsonNode; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.exception.ThingsboardCredentialsExpiredResponse; import org.thingsboard.server.exception.ThingsboardErrorResponse; import org.thingsboard.server.service.security.auth.rest.LoginRequest; import org.thingsboard.server.service.security.auth.rest.LoginResponse; import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.ExampleBuilder; import springfox.documentation.builders.OperationBuilder; import springfox.documentation.builders.RepresentationBuilder; import springfox.documentation.builders.RequestParameterBuilder; import springfox.documentation.builders.ResponseBuilder; +import springfox.documentation.schema.Example; import springfox.documentation.service.ApiDescription; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.ApiListing; @@ -74,6 +79,7 @@ import static java.util.function.Predicate.not; import static springfox.documentation.builders.PathSelectors.any; import static springfox.documentation.builders.PathSelectors.regex; +@Slf4j @Configuration public class SwaggerConfiguration { @@ -100,44 +106,30 @@ public class SwaggerConfiguration { @Value("${swagger.version}") private String version; - @Autowired - private CachingOperationNameGenerator operationNames; - @Bean public Docket thingsboardApi() { TypeResolver typeResolver = new TypeResolver(); - final ResolvedType jsonNodeType = - typeResolver.resolve( - JsonNode.class); - final ResolvedType stringType = - typeResolver.resolve( - String.class); - return new Docket(DocumentationType.OAS_30) .groupName("thingsboard") .apiInfo(apiInfo()) .additionalModels( typeResolver.resolve(ThingsboardErrorResponse.class), + typeResolver.resolve(ThingsboardCredentialsExpiredResponse.class), typeResolver.resolve(LoginRequest.class), typeResolver.resolve(LoginResponse.class) ) - /* .alternateTypeRules( - new AlternateTypeRule( - jsonNodeType, - stringType))*/ .select() .paths(apiPaths()) .paths(any()) .build() .globalResponses(HttpMethod.GET, - List.of( - new ResponseBuilder() - .code("401") - .description("Unauthorized") - .representation(MediaType.APPLICATION_JSON) - .apply(classRepresentation(ThingsboardErrorResponse.class, true)) - .build() - ) + defaultErrorResponses(false) + ) + .globalResponses(HttpMethod.POST, + defaultErrorResponses(true) + ) + .globalResponses(HttpMethod.DELETE, + defaultErrorResponses(false) ) .securitySchemes(newArrayList(httpLogin())) .securityContexts(newArrayList(securityContext())) @@ -146,15 +138,15 @@ public class SwaggerConfiguration { @Bean @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER) - ApiListingScannerPlugin loginEndpointListingScanner() { + ApiListingScannerPlugin loginEndpointListingScanner(final CachingOperationNameGenerator operationNames) { return new ApiListingScannerPlugin() { @Override public List apply(DocumentationContext context) { - return List.of(loginEndpointApiDescription()); + return List.of(loginEndpointApiDescription(operationNames)); } @Override - public boolean supports(DocumentationType delimiter) { + public boolean supports(@NotNull DocumentationType delimiter) { return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter); } }; @@ -176,7 +168,7 @@ public class SwaggerConfiguration { } @Override - public boolean supports(DocumentationType delimiter) { + public boolean supports(@NotNull DocumentationType delimiter) { return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter); } }; @@ -199,6 +191,7 @@ public class SwaggerConfiguration { .showCommonExtensions(false) .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS) .validatorUrl(null) + .persistAuthorization(true) .syntaxHighlightActivate(true) .syntaxHighlightTheme("agate") .build(); @@ -248,7 +241,7 @@ public class SwaggerConfiguration { .build(); } - private ApiDescription loginEndpointApiDescription() { + private ApiDescription loginEndpointApiDescription(final CachingOperationNameGenerator operationNames) { return new ApiDescription(null, "/api/auth/login", "Login method to get user JWT token data", "Login endpoint", Collections.singletonList( new OperationBuilder(operationNames) .summary("Login method to get user JWT token data") @@ -257,7 +250,8 @@ public class SwaggerConfiguration { .position(0) .codegenMethodNameStem("loginPost") .method(HttpMethod.POST) - .notes("Login method to get user JWT token data.\n\nValue of the response **token** field can be used as JWT token value for authorization.") + .notes("Login method used to authenticate user and get JWT token data.\n\nValue of the response **token** " + + "field can be used as **X-Authorization** header value:\n\n`X-Authorization: Bearer $JWT_TOKEN_VALUE`.") .requestParameters( List.of( new RequestParameterBuilder() @@ -278,7 +272,8 @@ public class SwaggerConfiguration { } private Collection loginResponses() { - return List.of( + List responses = new ArrayList<>(); + responses.add( new ResponseBuilder() .code("200") .description("OK") @@ -286,11 +281,82 @@ public class SwaggerConfiguration { .apply(classRepresentation(LoginResponse.class, true)). build() ); + responses.addAll(loginErrorResponses()); + return responses; } /** Helper methods **/ - private Consumer classRepresentation(Class clazz, boolean isResponse) { + private List defaultErrorResponses(boolean isPost) { + return List.of( + errorResponse("400", "Bad Request", + ThingsboardErrorResponse.of(isPost ? "Invalid request body" : "Invalid UUID string: 123", ThingsboardErrorCode.BAD_REQUEST_PARAMS, HttpStatus.BAD_REQUEST)), + errorResponse("401", "Unauthorized", + ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)), + errorResponse("403", "Forbidden", + ThingsboardErrorResponse.of("You don't have permission to perform this operation!", + ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN)), + errorResponse("404", "Not Found", + ThingsboardErrorResponse.of("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND, HttpStatus.NOT_FOUND)), + errorResponse("429", "Too Many Requests", + ThingsboardErrorResponse.of("Too many requests for current tenant!", + ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS)) + ); + } + + private List loginErrorResponses() { + return List.of( + errorResponse("401", "Unauthorized", + List.of( + errorExample("bad-credentials", "Bad credentials", + ThingsboardErrorResponse.of("Invalid username or password", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)), + errorExample("token-expired", "JWT token expired", + ThingsboardErrorResponse.of("Token has expired", ThingsboardErrorCode.JWT_TOKEN_EXPIRED, HttpStatus.UNAUTHORIZED)), + errorExample("account-disabled", "Disabled account", + ThingsboardErrorResponse.of("User account is not active", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)), + errorExample("account-locked", "Locked account", + ThingsboardErrorResponse.of("User account is locked due to security policy", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)), + errorExample("authentication-failed", "General authentication error", + ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)) + ) + ), + errorResponse("401 ", "Unauthorized (**Expired credentials**)", + List.of( + errorExample("credentials-expired", "Expired credentials", + ThingsboardCredentialsExpiredResponse.of("User password expired!", RandomStringUtils.randomAlphanumeric(30))) + ), ThingsboardCredentialsExpiredResponse.class + ) + ); + } + + private Response errorResponse(String code, String description, ThingsboardErrorResponse example) { + return errorResponse(code, description, List.of(errorExample("error-code-" + code, description, example))); + } + + private Response errorResponse(String code, String description, List examples) { + return errorResponse(code, description, examples, ThingsboardErrorResponse.class); + } + + private Response errorResponse(String code, String description, List examples, + Class errorResponseClass) { + return new ResponseBuilder() + .code(code) + .description(description) + .examples(examples) + .representation(MediaType.APPLICATION_JSON) + .apply(classRepresentation(errorResponseClass, true)) + .build(); + } + + private Example errorExample(String id, String summary, ThingsboardErrorResponse example) { + return new ExampleBuilder() + .mediaType(MediaType.APPLICATION_JSON_VALUE) + .summary(summary) + .id(id) + .value(example).build(); + } + + private Consumer classRepresentation(Class clazz, boolean isResponse) { return r -> r.model( m -> m.referenceModel(ref -> diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java index 1d2b78fae4..9dc95a3a05 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java @@ -15,9 +15,12 @@ */ package org.thingsboard.server.exception; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import org.springframework.http.HttpStatus; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; +@ApiModel public class ThingsboardCredentialsExpiredResponse extends ThingsboardErrorResponse { private final String resetToken; @@ -31,6 +34,7 @@ public class ThingsboardCredentialsExpiredResponse extends ThingsboardErrorRespo return new ThingsboardCredentialsExpiredResponse(message, resetToken); } + @ApiModelProperty(position = 5, value = "Password reset token", readOnly = true) public String getResetToken() { return resetToken; } diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java index 13d7b1e4a8..05df631f2c 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java @@ -15,11 +15,14 @@ */ package org.thingsboard.server.exception; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import org.springframework.http.HttpStatus; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import java.util.Date; +@ApiModel public class ThingsboardErrorResponse { // HTTP Response Status Code private final HttpStatus status; @@ -43,18 +46,35 @@ public class ThingsboardErrorResponse { return new ThingsboardErrorResponse(message, errorCode, status); } + @ApiModelProperty(position = 1, value = "HTTP Response Status Code", example = "401", readOnly = true) public Integer getStatus() { return status.value(); } + @ApiModelProperty(position = 2, value = "Error message", example = "Authentication failed", readOnly = true) public String getMessage() { return message; } + @ApiModelProperty(position = 3, value = "Platform error code:" + + "\n* `2` - General error (HTTP: 500 - Internal Server Error)" + + "\n\n* `10` - Authentication failed (HTTP: 401 - Unauthorized)" + + "\n\n* `11` - JWT token expired (HTTP: 401 - Unauthorized)" + + "\n\n* `15` - Credentials expired (HTTP: 401 - Unauthorized)" + + "\n\n* `20` - Permission denied (HTTP: 403 - Forbidden)" + + "\n\n* `30` - Invalid arguments (HTTP: 400 - Bad Request)" + + "\n\n* `31` - Bad request params (HTTP: 400 - Bad Request)" + + "\n\n* `32` - Item not found (HTTP: 404 - Not Found)" + + "\n\n* `33` - Too many requests (HTTP: 429 - Too Many Requests)" + + "\n\n* `34` - Too many updates (Too many updates over Websocket session)" + + "\n\n* `40` - Subscription violation (HTTP: 403 - Forbidden)", + example = "10", dataType = "integer", + readOnly = true) public ThingsboardErrorCode getErrorCode() { return errorCode; } + @ApiModelProperty(position = 4, value = "Timestamp", readOnly = true) public Date getTimestamp() { return timestamp; } diff --git a/pom.xml b/pom.xml index cf419aa9b4..ba162740c6 100755 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ 4.8.0 2.19.1 3.0.2 - 3.0.1 + 3.0.2 1.6.3 0.7 1.15.0 From 47b9892f80f20dd24ab4a7586afe244b266224cf Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 3 Nov 2021 16:12:52 +0200 Subject: [PATCH 192/303] UI: Improvement copy text in markdown (didn't work in HTTP) --- .../src/app/shared/components/marked-options.service.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/shared/components/marked-options.service.ts b/ui-ngx/src/app/shared/components/marked-options.service.ts index 97faf53118..729d6d5d5b 100644 --- a/ui-ngx/src/app/shared/components/marked-options.service.ts +++ b/ui-ngx/src/app/shared/components/marked-options.service.ts @@ -21,6 +21,7 @@ import { DOCUMENT } from '@angular/common'; import { WINDOW } from '@core/services/window.service'; import { Tokenizer } from 'marked'; import * as marked from 'marked'; +import { Clipboard } from '@angular/cdk/clipboard'; const copyCodeBlock = '{:copy-code}'; const codeStyleRegex = '^{:code-style="(.*)"}\n'; @@ -47,6 +48,7 @@ export class MarkedOptionsService extends MarkedOptions { private id = 1; constructor(private translate: TranslateService, + private clipboardService: Clipboard, @Inject(WINDOW) private readonly window: Window, @Inject(DOCUMENT) private readonly document: Document) { super(); @@ -162,7 +164,7 @@ export class MarkedOptionsService extends MarkedOptions { const copyWrapper = $('#codeWrapper' + id); if (copyWrapper.hasClass('noChars')) { const text = decodeURIComponent($('#copyCodeId' + id).text()); - this.window.navigator.clipboard.writeText(text).then(() => { + if (this.clipboardService.copy(text)) { import('tooltipster').then( () => { if (!copyWrapper.hasClass('tooltipstered')) { @@ -186,9 +188,8 @@ export class MarkedOptionsService extends MarkedOptions { } const tooltip = copyWrapper.tooltipster('instance'); tooltip.open(); - } - ); - }); + }); + } } } } From b3534942a5447e1e7f4419803e3ee2dd1796c68b Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 3 Nov 2021 16:18:00 +0200 Subject: [PATCH 193/303] Entity Id and Swagger description --- application/src/main/resources/thingsboard.yml | 2 +- .../java/org/thingsboard/server/common/data/id/EntityId.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index b7867360aa..40d9c105a1 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -849,7 +849,7 @@ swagger: security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api/.*}" non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/(?:noauth|v1)/.*}" title: "${SWAGGER_TITLE:ThingsBoard REST API}" - description: "${SWAGGER_DESCRIPTION:For instructions how to authorize requests please visit REST API documentation page.}" + description: "${SWAGGER_DESCRIPTION: ThingsBoard open-source IoT platform REST API documentation.}" contact: name: "${SWAGGER_CONTACT_NAME:Thingsboard team}" url: "${SWAGGER_CONTACT_URL:http://thingsboard.io}" diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java index 73b4a5b28f..d27aa43c7e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java @@ -36,10 +36,10 @@ public interface EntityId extends HasUUID, Serializable { //NOSONAR, the constan UUID NULL_UUID = UUID.fromString("13814000-1dd2-11b2-8080-808080808080"); - @ApiModelProperty(position = 1, required = true, value = "string", example = "784f394c-42b6-435a-983c-b7beff2784f9") + @ApiModelProperty(position = 1, required = true, value = "ID of the entity, time-based UUID v1", example = "784f394c-42b6-435a-983c-b7beff2784f9") UUID getId(); - @ApiModelProperty(position = 2, required = true, value = "string", example = "DEVICE") + @ApiModelProperty(position = 2, required = true, example = "DEVICE") EntityType getEntityType(); @JsonIgnore From 79588a7b708b23dec7d3ad356a36a08563d5aed6 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Nov 2021 16:45:01 +0200 Subject: [PATCH 194/303] Update help assets --- .../en_US/rulenode/common_node_script_args.md | 7 +- .../en_US/rulenode/filter_node_script_fn.md | 21 +- .../rulenode/generator_node_script_fn.md | 24 +- .../en_US/rulenode/switch_node_script_fn.md | 15 +- .../rulenode/transformation_node_script_fn.md | 26 +- .../en_US/widget/action/custom_action_fn.md | 126 +++++----- .../widget/action/custom_pretty_action_fn.md | 74 +++++- ...custom_action_back_first_and_open_state.md | 27 +++ .../custom_action_copy_access_token.md | 44 ++++ .../custom_action_delete_device_confirm.md | 33 +++ .../custom_action_display_alert.md | 35 +++ ...ustom_action_open_state_save_parameters.md | 34 +++ .../custom_action_return_previous_state.md | 18 ++ .../custom_pretty_clone_device_html.md | 46 ++++ .../custom_pretty_clone_device_js.md | 56 +++++ .../custom_pretty_create_dialog_html.md | 164 +++++++++++++ .../custom_pretty_create_dialog_js.md | 136 +++++++++++ .../custom_pretty_create_user_html.md | 81 +++++++ .../custom_pretty_create_user_js.md | 137 +++++++++++ .../custom_pretty_edit_dialog_html.md | 196 +++++++++++++++ .../custom_pretty_edit_dialog_js.md | 224 ++++++++++++++++++ .../custom_pretty_edit_image_html.md | 42 ++++ .../custom_pretty_edit_image_js.md | 85 +++++++ .../widget/config/datakey_postprocess_fn.md | 27 +++ .../widget/lib/entity/cell_content_fn.md | 82 +++++++ .../en_US/widget/lib/entity/cell_style_fn.md | 10 + .../en_US/widget/lib/entity/row_style_fn.md | 10 + .../widget/lib/flot/ticks_formatter_fn.md | 11 + .../lib/flot/tooltip_value_format_fn.md | 11 + .../images/rulenode/examples/filter-node.png | Bin 0 -> 21939 bytes .../images/rulenode/examples/switch-node.png | Bin 0 -> 37494 bytes 31 files changed, 1705 insertions(+), 97 deletions(-) create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_back_first_and_open_state.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_copy_access_token.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_delete_device_confirm.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_display_alert.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_open_state_save_parameters.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_return_previous_state.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_clone_device_html.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_clone_device_js.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_dialog_html.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_dialog_js.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_user_html.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_user_js.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_dialog_html.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_dialog_js.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_image_html.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_image_js.md create mode 100644 ui-ngx/src/assets/help/images/rulenode/examples/filter-node.png create mode 100644 ui-ngx/src/assets/help/images/rulenode/examples/switch-node.png diff --git a/ui-ngx/src/assets/help/en_US/rulenode/common_node_script_args.md b/ui-ngx/src/assets/help/en_US/rulenode/common_node_script_args.md index ef53ae37f8..296e5b735c 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/common_node_script_args.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/common_node_script_args.md @@ -1,8 +1,11 @@
    • msg: {[key: string]: any} - is a Message payload key/value object.
    • -
    • metadata: {[key: string]: string} - is a Message metadata key/value object. +
    • metadata: {[key: string]: string} - is a Message metadata key/value map, where both keys and values are strings.
    • -
    • msgType: string - is a string Message type. See MessageType enum for common used values. +
    • msgType: string - is a string containing Message type. See MessageType enum for common used values.
    + +Enable 'debug mode' for your rule node to see the messages that arrive in near real-time. +See Debugging for more information. \ No newline at end of file diff --git a/ui-ngx/src/assets/help/en_US/rulenode/filter_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/filter_node_script_fn.md index 3740d88c64..862590867b 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/filter_node_script_fn.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/filter_node_script_fn.md @@ -5,7 +5,7 @@ *function Filter(msg, metadata, msgType): boolean* -JavaScript function evaluating **true/false** condition on incoming Message. +JavaScript function defines a boolean expression based on the incoming Message and Metadata. **Parameters:** @@ -13,19 +13,34 @@ JavaScript function evaluating **true/false** condition on incoming Message. **Returns:** -Should return `boolean` value. If `true` - send Message via **True** chain, otherwise **False** chain is used. +Must return a `boolean` value. If `true` - routes Message to subsequent rule nodes that are related via **True** link, +otherwise sends Message to rule nodes related via **False** link. +Uses 'Failure' link in case of any failures to evaluate the expression.
    ##### Examples -* Forward all messages with `temperature` value greater than `20` to the **True** chain and all other messages to the **False** chain: +* Forward all messages with `temperature` value greater than `20` to the **True** link and all other messages to the **False** link. + Assumes that incoming messages always contain the 'temperature' field: ```javascript return msg.temperature > 20; {:copy-code} ``` + +Example of the rule chain configuration: + +![image](${helpBaseUrl}/help/images/rulenode/examples/filter-node.png) + +* Same as above, but checks that the message has 'temperature' field to **avoid failures** on unexpected messages: + +```javascript +return typeof msg.temperature !== 'undefined' && msg.temperature > 20; +{:copy-code} +``` + * Forward all messages with type `ATTRIBUTES_UPDATED` to the **True** chain and all other messages to the **False** chain: ```javascript diff --git a/ui-ngx/src/assets/help/en_US/rulenode/generator_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/generator_node_script_fn.md index b3f5bcd059..ac8b6abf56 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/generator_node_script_fn.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/generator_node_script_fn.md @@ -5,7 +5,7 @@ *function Generate(prevMsg, prevMetadata, prevMsgType): {msg: object, metadata: object, msgType: string}* -JavaScript function generating new message using previous Message payload, Metadata and Message type as input arguments. +JavaScript function generating new Message using previous Message payload, Metadata and Message type as input arguments. **Parameters:** @@ -24,13 +24,13 @@ Should return the object with the following structure: ```javascript { - msg?: {[key: string]: any}, - metadata?: {[key: string]: string}, - msgType?: string + msg: {[key: string]: any}, + metadata: {[key: string]: string}, + msgType: string } ``` -All fields in resulting object are optional and will be taken from previously generated Message if not specified. +All fields in resulting object are mandatory.
    @@ -39,14 +39,11 @@ All fields in resulting object are optional and will be taken from previously ge * Generate message of type `POST_TELEMETRY_REQUEST` with random `temperature` value from `18` to `32`: ```javascript -var temperature = 18 + Math.random() * 14; +var temperature = 18 + Math.random() * (32 - 18); // Round to at most 2 decimal places (optional) temperature = Math.round( temperature * 100 ) / 100; var msg = { temperature: temperature }; -var metadata = {}; -var msgType = "POST_TELEMETRY_REQUEST"; - -return { msg: msg, metadata: metadata, msgType: msgType }; +return { msg: msg, metadata: {}, msgType: "POST_TELEMETRY_REQUEST" }; {:copy-code} ``` @@ -62,9 +59,7 @@ and metadata with field data having value 40 ```javascript var msg = { temp: 42, humidity: 77 }; var metadata = { data: 40 }; -var msgType = "POST_TELEMETRY_REQUEST"; - -return { msg: msg, metadata: metadata, msgType: msgType }; +return { msg: msg, metadata: metadata, msgType: "POST_TELEMETRY_REQUEST" }; {:copy-code} ``` @@ -108,9 +103,8 @@ if (isDecrement === 'true') { var msg = { temperature: temperature }; var metadata = { isDecrement: isDecrement }; -var msgType = "POST_TELEMETRY_REQUEST"; -return { msg: msg, metadata: metadata, msgType: msgType }; +return { msg: msg, metadata: metadata, msgType: "POST_TELEMETRY_REQUEST" }; {:copy-code} ``` diff --git a/ui-ngx/src/assets/help/en_US/rulenode/switch_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/switch_node_script_fn.md index de08fb9020..a31eae72cf 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/switch_node_script_fn.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/switch_node_script_fn.md @@ -5,7 +5,7 @@ *function Switch(msg, metadata, msgType): string[]* -JavaScript function computing **an array of next Relation names** for incoming Message. +JavaScript function computing **an array of Link names** to forward the incoming Message. **Parameters:** @@ -13,8 +13,9 @@ JavaScript function computing **an array of next Relation names** for incoming M **Returns:** -Should return an array of `string` values presenting **next Relation names** where Message should be routed.
    -If returned array is empty - message will not be routed to any Node and discarded. +Should return an array of `string` values presenting **link names** that the Rule Engine should use to further route the incoming Message.
    +If the result is an empty array - message will not be routed to any Node and will be immediately +acknowledged.
    @@ -24,7 +25,7 @@ If returned array is empty - message will not be routed to any Node and discarde
  • Forward all messages with temperature value greater than 30 to the 'High temperature' chain,
    with temperature value lower than 20 to the 'Low temperature' chain and all other messages
    -to the 'Normal temperature' chain: +to the 'Other' chain:
  • @@ -34,11 +35,15 @@ if (msg.temperature > 30) { } else if (msg.temperature < 20) { return ['Low temperature']; } else { - return ['Normal temperature']; + return ['Other']; } {:copy-code} ``` +Example of the rule chain configuration: + +![image](${helpBaseUrl}/help/images/rulenode/examples/switch-node.png) +
    • For messages with type POST_TELEMETRY_REQUEST: diff --git a/ui-ngx/src/assets/help/en_US/rulenode/transformation_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/transformation_node_script_fn.md index acc49c623c..49f246a361 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/transformation_node_script_fn.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/transformation_node_script_fn.md @@ -5,7 +5,7 @@ *function Transform(msg, metadata, msgType): {msg: object, metadata: object, msgType: string}* -JavaScript function transforming input Message payload, Metadata or Message type. +The JavaScript function to transform input Message payload, Metadata and/or Message type to the output message. **Parameters:** @@ -29,11 +29,29 @@ All fields in resulting object are optional and will be taken from original mess ##### Examples -* Change message type to `CUSTOM_REQUEST`: +* Add sum of two fields ('a' and 'b') as a new field ('sum') of existing message: ```javascript -return { msgType: 'CUSTOM_REQUEST' }; -{:copy-code} +if(typeof msg.a !== "undefined" && typeof msg.b !== "undefined"){ + msg.sum = msg.a + msg.b; +} +return {msg: msg}; +``` + +* Transform value of the 'temperature' field from °F to °C: + +```javascript +msg.temperature = (msg.temperature - 32) * 5 / 9; +return {msg: msg}; +``` + +* Replace the incoming message with the new message that contains only one field - count of properties in the original message: + +```javascript +var newMsg = { + count: Object.keys(msg).length +}; +return {msg: newMsg}; ```
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/custom_action_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/custom_action_fn.md index 7ea3417f39..2bd143842d 100644 --- a/ui-ngx/src/assets/help/en_US/widget/action/custom_action_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/action/custom_action_fn.md @@ -17,67 +17,65 @@ A JavaScript function performing custom action. ##### Examples -* Display alert dialog with entity information: - -```javascript -{:code-style="max-height: 300px;"} -var title; -var content; -if (entityName) { - title = entityName + ' details'; - content = 'Entity name: ' + entityName; - if (additionalParams && additionalParams.entity) { - var entity = additionalParams.entity; - if (entity.id) { - content += '
        Entity type: ' + entity.id.entityType; - } - if (!isNaN(entity.temperature) && entity.temperature !== '') { - content += '
        Temperature: ' + entity.temperature + ' °C'; - } - } -} else { - title = 'No entity information available'; - content = 'No entity information available'; -} - -showAlertDialog(title, content); - -function showAlertDialog(title, content) { - setTimeout(function() { - widgetContext.dialogs.alert(title, content).subscribe(); - }, 100); -} -{:copy-code} -``` - -* Delete device after confirmation: - -```javascript -{:code-style="max-height: 300px;"} -var $injector = widgetContext.$scope.$injector; -var dialogs = $injector.get(widgetContext.servicesMap.get('dialogs')); -var deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); - -openDeleteDeviceDialog(); - -function openDeleteDeviceDialog() { - var title = 'Are you sure you want to delete the device ' + entityName + '?'; - var content = 'Be careful, after the confirmation, the device and all related data will become unrecoverable!'; - dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe( - function(result) { - if (result) { - deleteDevice(); - } - } - ); -} - -function deleteDevice() { - deviceService.deleteDevice(entityId.id).subscribe( - function() { - widgetContext.updateAliases(); - } - ); -} -{:copy-code} -``` +
        + +
        +
        + +
        + +
        +
        + +
        + +
        +
        + +
        + +
        +
        + +
        + +
        +
        + +
        + +
        +
        + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/custom_pretty_action_fn.md b/ui-ngx/src/assets/help/en_US/widget/action/custom_pretty_action_fn.md index a4c20a7cad..e82eab1e73 100644 --- a/ui-ngx/src/assets/help/en_US/widget/action/custom_pretty_action_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/action/custom_pretty_action_fn.md @@ -42,7 +42,7 @@ A JavaScript function performing custom action with defined HTML template to ren
        +
        + +###### Display dialog to created new user + +
        + +
        +
        + +
        + +
        +
        + +###### Display dialog to add/edit image in entity attribute + +
        + +
        +
        + +
        + +
        +
        + +###### Display dialog to clone device + +
        + +
        +
        + +
        + +
        0) { + stateIndex -= 1; + backToPrevState(stateIndex); +} +openDashboardState('devices'); + +function backToPrevState(stateIndex) { + widgetContext.stateController.navigatePrevState(stateIndex); +} + +function openDashboardState(statedId) { + var currentState = widgetContext.stateController.getStateId(); + if (currentState !== statedId) { + var params = {}; + widgetContext.stateController.updateState(statedId, params, false); + } +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_copy_access_token.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_copy_access_token.md new file mode 100644 index 0000000000..975883f7f8 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_copy_access_token.md @@ -0,0 +1,44 @@ +#### Function copy device access token to buffer + +```javascript +{:code-style="max-height: 400px;"} +var $injector = widgetContext.$scope.$injector; +var deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); +var $translate = $injector.get(widgetContext.servicesMap.get('translate')); +var $scope = widgetContext.$scope; +if (entityId.id && entityId.entityType === 'DEVICE') { + deviceService.getDeviceCredentials(entityId.id, true).subscribe( + (deviceCredentials) => { + var credentialsId = deviceCredentials.credentialsId; + if (copyToClipboard(credentialsId)) { + $scope.showSuccessToast($translate.instant('device.accessTokenCopiedMessage'), 750, "top", "left"); + } + } + ); +} + +function copyToClipboard(text) { + if (window.clipboardData && window.clipboardData.setData) { + return window.clipboardData.setData("Text", text); + } + else if (document.queryCommandSupported && document.queryCommandSupported("copy")) { + var textarea = document.createElement("textarea"); + textarea.textContent = text; + textarea.style.position = "fixed"; + document.body.appendChild(textarea); + textarea.select(); + try { + return document.execCommand("copy"); + } + catch (ex) { + console.warn("Copy to clipboard failed.", ex); + return false; + } + document.body.removeChild(textarea); + } +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_delete_device_confirm.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_delete_device_confirm.md new file mode 100644 index 0000000000..83ba86c348 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_delete_device_confirm.md @@ -0,0 +1,33 @@ +#### Function delete device after confirmation + +```javascript +var $injector = widgetContext.$scope.$injector; +var dialogs = $injector.get(widgetContext.servicesMap.get('dialogs')); +var deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); + +openDeleteDeviceDialog(); + +function openDeleteDeviceDialog() { + var title = 'Are you sure you want to delete the device ' + entityName + '?'; + var content = 'Be careful, after the confirmation, the device and all related data will become unrecoverable!'; + dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe( + function(result) { + if (result) { + deleteDevice(); + } + } + ); +} + +function deleteDevice() { + deviceService.deleteDevice(entityId.id).subscribe( + function() { + widgetContext.updateAliases(); + } + ); +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_display_alert.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_display_alert.md new file mode 100644 index 0000000000..bf6ed2b6fd --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_display_alert.md @@ -0,0 +1,35 @@ +#### Function display alert dialog with entity information + +```javascript +{:code-style="max-height: 400px;"} +var title; +var content; +if (entityName) { + title = entityName + ' details'; + content = 'Entity name: ' + entityName; + if (additionalParams && additionalParams.entity) { + var entity = additionalParams.entity; + if (entity.id) { + content += '
        Entity type: ' + entity.id.entityType; + } + if (!isNaN(entity.temperature) && entity.temperature !== '') { + content += '
        Temperature: ' + entity.temperature + ' °C'; + } + } +} else { + title = 'No entity information available'; + content = 'No entity information available'; +} + +showAlertDialog(title, content); + +function showAlertDialog(title, content) { + setTimeout(function() { + widgetContext.dialogs.alert(title, content).subscribe(); + }, 100); +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_open_state_save_parameters.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_open_state_save_parameters.md new file mode 100644 index 0000000000..18bd3f53ab --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_open_state_save_parameters.md @@ -0,0 +1,34 @@ +#### Function open state conditionally with saving particular state parameters + +```javascript +{:code-style="max-height: 400px;"} +var entitySubType; +var $injector = widgetContext.$scope.$injector; +$injector.get(widgetContext.servicesMap.get('entityService')).getEntity(entityId.entityType, entityId.id) + .subscribe(function(data) { + entitySubType = data.type; + if (entitySubType == 'energy meter') { + openDashboardStates('energy_meter_details_view'); + } else if (entitySubType == 'thermometer') { + openDashboardStates('thermometer_details_view'); + } + }); + +function openDashboardStates(statedId) { + var stateParams = widgetContext.stateController.getStateParams(); + var params = { + entityId: entityId, + entityName: entityName + }; + + if (stateParams.city) { + params.city = stateParams.city; + } + + widgetContext.stateController.openState(statedId, params, false); +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_return_previous_state.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_return_previous_state.md new file mode 100644 index 0000000000..77f65edbe7 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_action/custom_action_return_previous_state.md @@ -0,0 +1,18 @@ +#### Function return to the previous state + +```javascript +{:code-style="max-height: 400px;"} +let stateIndex = widgetContext.stateController.getStateIndex(); +if (stateIndex > 0) { + stateIndex -= 1; + backToPrevState(stateIndex); +} + +function backToPrevState(stateIndex) { + widgetContext.stateController.navigatePrevState(stateIndex); +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_clone_device_html.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_clone_device_html.md new file mode 100644 index 0000000000..7f93d6266b --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_clone_device_html.md @@ -0,0 +1,46 @@ +#### HTML template of dialog to clone device + +```html +{:code-style="max-height: 400px;"} +
        + +

        Clone device: {{ deviceName }}

        + + +
        + + +
        +
        + + Clone device name + + + Clone device name is required + + +
        +
        + + +
        +
        +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_clone_device_js.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_clone_device_js.md new file mode 100644 index 0000000000..2ee9160cce --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_clone_device_js.md @@ -0,0 +1,56 @@ +#### Function displaying dialog to clone device + +```javascript +{:code-style="max-height: 400px;"} +const $injector = widgetContext.$scope.$injector; +const customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +const attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); +const deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); +const rxjs = widgetContext.rxjs; + +openCloneDeviceDialog(); + +function openCloneDeviceDialog() { + customDialog.customDialog(htmlTemplate, CloneDeviceDialogController).subscribe(); +} + +function CloneDeviceDialogController(instance) { + let vm = instance; + vm.deviceName = entityName; + + vm.cloneDeviceFormGroup = vm.fb.group({ + cloneName: ['', [vm.validators.required]] + }); + + vm.save = function() { + deviceService.getDevice(entityId.id).pipe( + rxjs.mergeMap((origDevice) => { + let cloneDevice = { + name: vm.cloneDeviceFormGroup.get('cloneName').value, + type: origDevice.type + }; + return deviceService.saveDevice(cloneDevice).pipe( + rxjs.mergeMap((newDevice) => { + return attributeService.getEntityAttributes(origDevice.id, 'SERVER_SCOPE').pipe( + rxjs.mergeMap((origAttributes) => { + return attributeService.saveEntityAttributes(newDevice.id, 'SERVER_SCOPE', origAttributes); + }) + ); + }) + ); + }) + ).subscribe(() => { + widgetContext.updateAliases(); + vm.dialogRef.close(null); + }); + }; + + vm.cancel = function() { + vm.dialogRef.close(null); + }; +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_dialog_html.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_dialog_html.md new file mode 100644 index 0000000000..567e093c76 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_dialog_html.md @@ -0,0 +1,164 @@ +#### HTML template of dialog to create a device or an asset + +```html +{:code-style="max-height: 400px;"} +
        + +

        Add entity

        + + +
        + + +
        +
        +
        + + Entity Name + + + Entity name is required. + + + + Entity Label + + +
        +
        + + + +
        +
        +
        + + Latitude + + + + Longitude + + +
        +
        + + Address + + + + Owner + + +
        +
        + + Integer Value + + + Invalid integer value. + + +
        + + + + +
        +
        +
        +
        +
        Relations
        +
        +
        +
        +
        +
        + + Direction + + + + + + + Relation direction is required. + + + + +
        +
        + + +
        +
        +
        + +
        +
        +
        +
        +
        + +
        +
        +
        +
        + + +
        +
        +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_dialog_js.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_dialog_js.md new file mode 100644 index 0000000000..5dda1b524c --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_dialog_js.md @@ -0,0 +1,136 @@ +#### Function displaying dialog to create a device or an asset + +```javascript +{:code-style="max-height: 400px;"} +let $injector = widgetContext.$scope.$injector; +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +let assetService = $injector.get(widgetContext.servicesMap.get('assetService')); +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); +let entityRelationService = $injector.get(widgetContext.servicesMap.get('entityRelationService')); + +openAddEntityDialog(); + +function openAddEntityDialog() { + customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe(); +} + +function AddEntityDialogController(instance) { + let vm = instance; + + vm.allowedEntityTypes = ['ASSET', 'DEVICE']; + vm.entitySearchDirection = { + from: "FROM", + to: "TO" + } + + vm.addEntityFormGroup = vm.fb.group({ + entityName: ['', [vm.validators.required]], + entityType: ['DEVICE'], + entityLabel: [null], + type: ['', [vm.validators.required]], + attributes: vm.fb.group({ + latitude: [null], + longitude: [null], + address: [null], + owner: [null], + number: [null, [vm.validators.pattern(/^-?[0-9]+$/)]], + booleanValue: [null] + }), + relations: vm.fb.array([]) + }); + + vm.cancel = function () { + vm.dialogRef.close(null); + }; + + vm.relations = function () { + return vm.addEntityFormGroup.get('relations'); + }; + + vm.addRelation = function () { + vm.relations().push(vm.fb.group({ + relatedEntity: [null, [vm.validators.required]], + relationType: [null, [vm.validators.required]], + direction: [null, [vm.validators.required]] + })); + }; + + vm.removeRelation = function (index) { + vm.relations().removeAt(index); + vm.relations().markAsDirty(); + }; + + vm.save = function () { + vm.addEntityFormGroup.markAsPristine(); + saveEntityObservable().subscribe( + function (entity) { + widgetContext.rxjs.forkJoin([ + saveAttributes(entity.id), + saveRelations(entity.id) + ]).subscribe( + function () { + widgetContext.updateAliases(); + vm.dialogRef.close(null); + } + ); + } + ); + }; + + function saveEntityObservable() { + const formValues = vm.addEntityFormGroup.value; + let entity = { + name: formValues.entityName, + type: formValues.type, + label: formValues.entityLabel + }; + if (formValues.entityType == 'ASSET') { + return assetService.saveAsset(entity); + } else if (formValues.entityType == 'DEVICE') { + return deviceService.saveDevice(entity); + } + } + + function saveAttributes(entityId) { + let attributes = vm.addEntityFormGroup.get('attributes').value; + let attributesArray = []; + for (let key in attributes) { + if (attributes[key] !== null) { + attributesArray.push({key: key, value: attributes[key]}); + } + } + if (attributesArray.length > 0) { + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray); + } + return widgetContext.rxjs.of([]); + } + + function saveRelations(entityId) { + let relations = vm.addEntityFormGroup.get('relations').value; + let tasks = []; + for (let i = 0; i < relations.length; i++) { + let relation = { + type: relations[i].relationType, + typeGroup: 'COMMON' + }; + if (relations[i].direction == 'FROM') { + relation.to = relations[i].relatedEntity; + relation.from = entityId; + } else { + relation.to = entityId; + relation.from = relations[i].relatedEntity; + } + tasks.push(entityRelationService.saveRelation(relation)); + } + if (tasks.length > 0) { + return widgetContext.rxjs.forkJoin(tasks); + } + return widgetContext.rxjs.of([]); + } +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_user_html.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_user_html.md new file mode 100644 index 0000000000..c523258fbc --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_user_html.md @@ -0,0 +1,81 @@ +#### HTML template of dialog to create new user + +```html +{:code-style="max-height: 400px;"} +
        + +

        Add new User

        + + +
        + + +
        +
        +
        +
        + + Email + + + Email is required + + + Invalid email format + + +
        +
        + + First Name + + +
        +
        + + Last Name + + +
        +
        + + User activation method + + + {{activationMethod.name}} + + + Please choose activation method + e.g. Send activation email + +
        +
        +
        + + +
        +
        +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_user_js.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_user_js.md new file mode 100644 index 0000000000..22738c53c1 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_create_user_js.md @@ -0,0 +1,137 @@ +#### Function displaying dialog to create new user + +```javascript +{:code-style="max-height: 400px;"} +const $injector = widgetContext.$scope.$injector; +const customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +const userService = $injector.get(widgetContext.servicesMap.get('userService')); +const $scope = widgetContext.$scope; +const rxjs = widgetContext.rxjs; + +openAddUserDialog(); + +function openAddUserDialog() { + customDialog.customDialog(htmlTemplate, AddUserDialogController).subscribe(); +} + +function AddUserDialogController(instance) { + let vm = instance; + + vm.currentUser = widgetContext.currentUser; + + vm.addEntityFormGroup = vm.fb.group({ + email: ['', [vm.validators.required, vm.validators.pattern(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\_\-0-9]+\.)+[a-zA-Z]{2,}))$/)]], + firstName: [''], + lastName: ['', ], + userActivationMethod: ['', [vm.validators.required]] + }); + + vm.activationMethods = [ + { + value: 'displayActivationLink', + name: 'Display activation link' + }, + { + value: 'sendActivationMail', + name: 'Send activation email' + } + ]; + + vm.cancel = function() { + vm.dialogRef.close(null); + }; + + vm.save = function() { + let formObj = vm.addEntityFormGroup.getRawValue(); + let attributes = []; + let sendActivationMail = false; + let newUser = { + email: formObj.email, + firstName: formObj.firstName, + lastName: formObj.lastName, + authority: 'TENANT_ADMIN' + }; + + if (formObj.userActivationMethod === 'sendActivationMail') { + sendActivationMail = true; + } + + userService.saveUser(newUser, sendActivationMail).pipe( + rxjs.mergeMap((user) => { + let activationObs; + if (sendActivationMail) { + activationObs = rxjs.of(null); + } else { + activationObs = userService.getActivationLink(user.id.id); + } + return activationObs.pipe( + rxjs.mergeMap((activationLink) => { + return activationLink ? customDialog.customDialog(activationLinkDialogTemplate, ActivationLinkDialogController, {"activationLink": activationLink}) : rxjs.of(null); + }) + ); + }) + ).subscribe(() => { + vm.dialogRef.close(null); + }); + }; +} + +function ActivationLinkDialogController(instance) { + let vm = instance; + + vm.activationLink = vm.data.activationLink; + + vm.onActivationLinkCopied = () => { + $scope.showSuccessToast("User activation link has been copied to clipboard", 1200, "bottom", "left", "activationLinkDialogContent"); + }; + + vm.close = () => { + vm.dialogRef.close(null); + }; +} + +let activationLinkDialogTemplate = `
        + +

        user.activation-link

        + + +
        + + +
        +
        +
        + +
        +
        {{ activationLink }}
        + +
        +
        +
        +
        + +
        +
        `; +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_dialog_html.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_dialog_html.md new file mode 100644 index 0000000000..4e3cd0c608 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_dialog_html.md @@ -0,0 +1,196 @@ +#### HTML template of dialog to edit a device or an asset + +```html +{:code-style="max-height: 400px;"} +
        + +

        Edit

        + + +
        + + +
        +
        +
        + + Entity Name + + + + Entity Label + + +
        +
        + + Entity Type + + + + Type + + +
        +
        +
        + + Latitude + + + + Longitude + + +
        +
        + + Address + + + + Owner + + +
        +
        + + Integer Value + + + Invalid integer value. + + +
        + + + + +
        +
        +
        +
        +
        Relations
        +
        +
        +
        +
        +
        + + Direction + + + + + + + Relation direction is required. + + + + +
        +
        + + +
        +
        +
        + +
        +
        +
        +
        +
        +
        +
        New Relations
        +
        +
        +
        +
        +
        + + Direction + + + + + + + Relation direction is required. + + + + +
        +
        + + +
        +
        +
        + +
        +
        +
        +
        +
        + +
        +
        +
        +
        + + +
        +
        +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_dialog_js.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_dialog_js.md new file mode 100644 index 0000000000..b2a6a635df --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_dialog_js.md @@ -0,0 +1,224 @@ +#### Function displaying dialog to edit a device or an asset + +```javascript +{:code-style="max-height: 400px;"} +let $injector = widgetContext.$scope.$injector; +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +let entityService = $injector.get(widgetContext.servicesMap.get('entityService')); +let assetService = $injector.get(widgetContext.servicesMap.get('assetService')); +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); +let entityRelationService = $injector.get(widgetContext.servicesMap.get('entityRelationService')); + +openEditEntityDialog(); + +function openEditEntityDialog() { + customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe(); +} + +function EditEntityDialogController(instance) { + let vm = instance; + + vm.entityName = entityName; + vm.entityType = entityId.entityType; + vm.entitySearchDirection = { + from: "FROM", + to: "TO" + }; + vm.attributes = {}; + vm.oldRelationsData = []; + vm.relationsToDelete = []; + vm.entity = {}; + + vm.editEntityFormGroup = vm.fb.group({ + entityName: ['', [vm.validators.required]], + entityType: [null], + entityLabel: [null], + type: ['', [vm.validators.required]], + attributes: vm.fb.group({ + latitude: [null], + longitude: [null], + address: [null], + owner: [null], + number: [null, [vm.validators.pattern(/^-?[0-9]+$/)]], + booleanValue: [false] + }), + oldRelations: vm.fb.array([]), + relations: vm.fb.array([]) + }); + + getEntityInfo(); + + vm.cancel = function() { + vm.dialogRef.close(null); + }; + + vm.relations = function() { + return vm.editEntityFormGroup.get('relations'); + }; + + vm.oldRelations = function() { + return vm.editEntityFormGroup.get('oldRelations'); + }; + + vm.addRelation = function() { + vm.relations().push(vm.fb.group({ + relatedEntity: [null, [vm.validators.required]], + relationType: [null, [vm.validators.required]], + direction: [null, [vm.validators.required]] + })); + }; + + function addOldRelation() { + vm.oldRelations().push(vm.fb.group({ + relatedEntity: [{value: null, disabled: true}, [vm.validators.required]], + relationType: [{value: null, disabled: true}, [vm.validators.required]], + direction: [{value: null, disabled: true}, [vm.validators.required]] + })); + } + + vm.removeRelation = function(index) { + vm.relations().removeAt(index); + vm.relations().markAsDirty(); + }; + + vm.removeOldRelation = function(index) { + vm.oldRelations().removeAt(index); + vm.relationsToDelete.push(vm.oldRelationsData[index]); + vm.oldRelations().markAsDirty(); + }; + + vm.save = function() { + vm.editEntityFormGroup.markAsPristine(); + widgetContext.rxjs.forkJoin([ + saveAttributes(entityId), + saveRelations(entityId), + saveEntity() + ]).subscribe( + function () { + widgetContext.updateAliases(); + vm.dialogRef.close(null); + } + ); + }; + + function getEntityAttributes(attributes) { + for (var i = 0; i < attributes.length; i++) { + vm.attributes[attributes[i].key] = attributes[i].value; + } + } + + function getEntityRelations(relations) { + let relationsFrom = relations[0]; + let relationsTo = relations[1]; + for (let i=0; i < relationsFrom.length; i++) { + let relation = { + direction: 'FROM', + relationType: relationsFrom[i].type, + relatedEntity: relationsFrom[i].to + }; + vm.oldRelationsData.push(relation); + addOldRelation(); + } + for (let i=0; i < relationsTo.length; i++) { + let relation = { + direction: 'TO', + relationType: relationsTo[i].type, + relatedEntity: relationsTo[i].from + }; + vm.oldRelationsData.push(relation); + addOldRelation(); + } + } + + function getEntityInfo() { + widgetContext.rxjs.forkJoin([ + entityRelationService.findInfoByFrom(entityId), + entityRelationService.findInfoByTo(entityId), + attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE'), + entityService.getEntity(entityId.entityType, entityId.id) + ]).subscribe( + function (data) { + getEntityRelations(data.slice(0,2)); + getEntityAttributes(data[2]); + vm.entity = data[3]; + vm.editEntityFormGroup.patchValue({ + entityName: vm.entity.name, + entityType: vm.entityType, + entityLabel: vm.entity.label, + type: vm.entity.type, + attributes: vm.attributes, + oldRelations: vm.oldRelationsData + }, {emitEvent: false}); + } + ); + } + + function saveEntity() { + const formValues = vm.editEntityFormGroup.value; + if (vm.entity.label !== formValues.entityLabel){ + vm.entity.label = formValues.entityLabel; + if (formValues.entityType == 'ASSET') { + return assetService.saveAsset(vm.entity); + } else if (formValues.entityType == 'DEVICE') { + return deviceService.saveDevice(vm.entity); + } + } + return widgetContext.rxjs.of([]); + } + + function saveAttributes(entityId) { + let attributes = vm.editEntityFormGroup.get('attributes').value; + let attributesArray = []; + for (let key in attributes) { + if (attributes[key] !== vm.attributes[key]) { + attributesArray.push({key: key, value: attributes[key]}); + } + } + if (attributesArray.length > 0) { + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray); + } + return widgetContext.rxjs.of([]); + } + + function saveRelations(entityId) { + let relations = vm.editEntityFormGroup.get('relations').value; + let tasks = []; + for(let i=0; i < relations.length; i++) { + let relation = { + type: relations[i].relationType, + typeGroup: 'COMMON' + }; + if (relations[i].direction == 'FROM') { + relation.to = relations[i].relatedEntity; + relation.from = entityId; + } else { + relation.to = entityId; + relation.from = relations[i].relatedEntity; + } + tasks.push(entityRelationService.saveRelation(relation)); + } + for (let i=0; i < vm.relationsToDelete.length; i++) { + let relation = { + type: vm.relationsToDelete[i].relationType + }; + if (vm.relationsToDelete[i].direction == 'FROM') { + relation.to = vm.relationsToDelete[i].relatedEntity; + relation.from = entityId; + } else { + relation.to = entityId; + relation.from = vm.relationsToDelete[i].relatedEntity; + } + tasks.push(entityRelationService.deleteRelation(relation.from, relation.type, relation.to)); + } + if (tasks.length > 0) { + return widgetContext.rxjs.forkJoin(tasks); + } + return widgetContext.rxjs.of([]); + } +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_image_html.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_image_html.md new file mode 100644 index 0000000000..3f2eff11c6 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_image_html.md @@ -0,0 +1,42 @@ +#### HTML template of dialog to add/edit image in entity attribute + +```html +{:code-style="max-height: 400px;"} +
        + +

        Edit {{entityName}} image

        + + +
        + + +
        +
        +
        + +
        +
        +
        + + +
        +
        +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_image_js.md b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_image_js.md new file mode 100644 index 0000000000..21acb89321 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/examples_custom_pretty/custom_pretty_edit_image_js.md @@ -0,0 +1,85 @@ +#### Function displaying dialog to add/edit image in entity attribute + +```javascript +{:code-style="max-height: 400px;"} +let $injector = widgetContext.$scope.$injector; +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +let assetService = $injector.get(widgetContext.servicesMap.get('assetService')); +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); +let entityService = $injector.get(widgetContext.servicesMap.get('entityService')); + +openAddEntityDialog(); + +function openAddEntityDialog() { + customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe(() => {}); +} + +function AddEntityDialogController(instance) { + let vm = instance; + + vm.entityName = entityName; + + vm.attributes = {}; + + vm.editEntity = vm.fb.group({ + attributes: vm.fb.group({ + image: [null] + }) + }); + + getEntityInfo(); + + vm.cancel = function() { + vm.dialogRef.close(null); + }; + + vm.save = function() { + vm.loading = true; + saveAttributes(entityId).subscribe( + () => { + vm.dialogRef.close(null); + }, () =>{ + vm.loading = false; + } + ); + }; + + function getEntityAttributes(attributes) { + for (var i = 0; i < attributes.length; i++) { + vm.attributes[attributes[i].key] = attributes[i].value; + } + } + + function getEntityInfo() { + vm.loading = true; + attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE').subscribe( + function (data) { + getEntityAttributes(data); + + vm.editEntity.patchValue({ + attributes: vm.attributes + }, {emitEvent: false}); + vm.loading = false; + } + ); + } + + function saveAttributes(entityId) { + let attributes = vm.editEntity.get('attributes').value; + let attributesArray = []; + for (let key in attributes) { + if (attributes[key] !== vm.attributes[key]) { + attributesArray.push({key: key, value: attributes[key]}); + } + } + if (attributesArray.length > 0) { + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray); + } + return widgetContext.rxjs.of([]); + } +} +{:copy-code} +``` + +
        +
        diff --git a/ui-ngx/src/assets/help/en_US/widget/config/datakey_postprocess_fn.md b/ui-ngx/src/assets/help/en_US/widget/config/datakey_postprocess_fn.md index acab47c45e..fc4999757a 100644 --- a/ui-ngx/src/assets/help/en_US/widget/config/datakey_postprocess_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/config/datakey_postprocess_fn.md @@ -54,6 +54,33 @@ if (prevOrigValue) { } {:copy-code} ``` +* Formatting data to time format + +```javascript +if (value) { + return moment(value).format("DD/MM/YYYY HH:mm:ss"); +} +return ''; +{:copy-code} +``` + +* Creates line-breaks for 0 values, when used in line chart + +```javascript +if (value === 0) { + return null; +} else { + return value; +} +{:copy-code} +``` + +* Display data point of the HTML value card under the condition + +```javascript +return value ? '
        Temperature: '+value+' °C
        ' : ''; +{:copy-code} +```

        diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_content_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_content_fn.md index 4458177327..e2dd12e841 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_content_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_content_fn.md @@ -57,5 +57,87 @@ return '
        ⬤'; +{:copy-code} +``` + +* Decimal value format (1196 => 1,196.0): + +```javascript +var value = value / 1; +function numberWithCommas(x) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); +} +return value ? numberWithCommas(value.toFixed(1)) : ''; +{:copy-code} +``` + +* Show device status and icon this : + +```javascript +{:code-style="max-height: 200px; max-width: 850px;"} +function getIcon(value) { + if (value == 'QUEUED') { + return '' + + '' + + '' + + '' + + ''; + } + if (value == 'UPDATED' ) { + return '' + + 'update' + + ''; + } + return ''; +} +function capitalize (s) { + if (typeof s !== 'string') return ''; + return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); +} +var status = value; +return getIcon(status) + '' + capitalize(status) + ''; +{:copy-code} +``` + +* Display device attribute value on progress bar: + +```javascript +{:code-style="max-height: 200px; max-width: 850px;"} +var progress = value; +if (value !== '') { + return `` + + `` + + ``; +} +{:copy-code} +``` +

        diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_style_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_style_fn.md index 692960cf4a..442fca3375 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_style_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entity/cell_style_fn.md @@ -29,6 +29,16 @@ Should return key/value object presenting style attributes. ##### Examples +* Set color and font-weight table cell content: + +```javascript +return { + color:'rgb(0, 132, 214)', + fontWeight: 600 +} +{:copy-code} +``` + * Set color depending on device temperature value: ```javascript diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entity/row_style_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entity/row_style_fn.md index f91befddce..4867cb9b38 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entity/row_style_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entity/row_style_fn.md @@ -27,6 +27,16 @@ Should return key/value object presenting style attributes. ##### Examples +* Set color and font-weight table row: + +```javascript +return { + color:'rgb(0, 132, 214)', + fontWeight: 600 +} +{:copy-code} +``` + * Set row background color depending on device type: ```javascript diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/flot/ticks_formatter_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/flot/ticks_formatter_fn.md index 673161c58d..12de0f782c 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/flot/ticks_formatter_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/flot/ticks_formatter_fn.md @@ -43,6 +43,17 @@ return ''; {:copy-code} ``` +* Present ticks in decimal format (1196 => 1,196.0): + +```javascript +var value = value / 1; +function numberWithCommas(x) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); +} +return value ? numberWithCommas(value.toFixed(1)) : ''; +{:copy-code} +``` +
        • To present axis ticks for true / false or 1 / 0 data.
          diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/flot/tooltip_value_format_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/flot/tooltip_value_format_fn.md index 4ff02e3fab..bffbfe4673 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/flot/tooltip_value_format_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/flot/tooltip_value_format_fn.md @@ -36,5 +36,16 @@ return value.toFixed(2) + ' A'; {:copy-code} ``` +* Present the datapoint value in decimal format (1196 => 1,196.0): + +```javascript +var value = value / 1; +function numberWithCommas(x) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); +} +return value ? numberWithCommas(value.toFixed(1)) : ''; +{:copy-code} +``` +

          diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/filter-node.png b/ui-ngx/src/assets/help/images/rulenode/examples/filter-node.png new file mode 100644 index 0000000000000000000000000000000000000000..178df7e314ef08bac2e6a476cf121e772de4d42d GIT binary patch literal 21939 zcmcG$Rajk1w*`p1ySo!KxVr>*w+#`T;K7}Zy99T44=x)g5Zr|%MNpxbN=SAFl7xZU%UCNVagr?vn+nE3 z^e2vm_J#hWMv5H~Df%{vLi#&8O7gGxe-yuiT0m;V$qt&2N4Ak9hk~s zS#qNzgKpm`VGYQu1rdn};Xo7?6R5(dgeb=xx4dGm0rC$-YsfTTud;?11^&G^&)}$IZzNARa3fGeK(s(C8tCO zoHav>H?<@!DJ~YU^fYk#+}NF@$EKpQA|5ttp@@>CqA&3|GkEQLv}~cLz&+=C`w0QA zFq_z&G}H8tJ$_5R+M{-w6P@Uht^~M;)SaaNa}P5XfxrdM02e4PPr`ZozqjzZKB5NQ zkk!2gU06@k>lTv#G4{g$Yizs-uCHMeuMgj8<^eBX&bs3fruDXG;^Pq}Ka#vlRS5LX z3wZF2ZSzwK&X*R&7O)qZxah`)U_sI+=D%Gm%oYs>Go7FH2>brSF>Hja58_Br8Hvuzqy{@v*}B+#wGt0T%Q1*Xrl>QNO5t59DY z=`>iCqi9z+ZVwx|>7PGdGE~yM`u1p66kw%S_j7H+11sKv@N=3{FKqD)XyD)I2f8iJ zgMHXntax9qhwG~gHUxNuUagu6!xa$`;n~=O+9Q`huh|=f@A;xkzrDS!tPA*h5K)pK zA+Txdf1P$fO&&NOQ3aGFnt5v1?-+6^*s%PXWp}Zl^cG%jI>fsoY8K+uVH}@C8m_Rv z_`8QhC|H2eoi43N(7q`untxXuo7_)=`t6C-zdwszAx1=V*arNC zPSag3mkw-w`p)J(vSvyb*5Lu1Ak<(!8bsI2avlv+AOmt#MBIFJuV_pDGV^+oKRYYl zVi5g=(1N)llC!57kwF<9i4C8GX`&Em-e1>weJZb(ldKl?A!oaKL#|YttGKTHD+UKR z5Yd?^+dKCm=-^CGz#S5RT@}5TQf70$yr%wEhO$e-+9vpgO2|nB#^4hi2~*?^ZFwHq zU~|C4I=)6AF7}~*uuf*H^cHDYNZ;Syz5+b1ly&{_0;URQy1gCRMosu70qP}jD6Z3> zzOW+6>zeNh+Q!54?KO4H?y`1E+MX2ecZGPJtzMzIObze4mmMo{;Q~_KnwOgdCAt$O$Is zq?#z^V0w9Jj-$n_Bd`i}k0m{05$YQmX-7&343<|D zims){q9x_xYG6J6??&H1|dksl2oZpL8dh<6r5@$ zoxKQ9)=FvmS~1n{NVnZhAQL~#Wq5Xp5TMy;xFS0Vu#$Yq^Ch*g*31xOwn^$?7xxg1vTl^2uX$bw3%3fBCKfvC0bgXpRLU+9w;6GOmA{ z*#Ed$qo$SAsgi09gea=8%#Z)qDGsRQV0o*|C+MQ@C&Xk<+au5OphDV5s29uf=k)tD zKERjhsF%HWO5@kB`5AZq27UXtN{Ih=3z?5u@>URSxcP+_4{eC{t=^fmCm$9i7xwcT zra;4@j}AkzeHIFT8mxaS*-I%0(k2c(ZZfA^BqZRriM#UsUT*YPr{<+4_wMSC-!Tnr zi;>?H6vmrIkFq9mg3LwB8LCqjeJrw!dXj;}xdfNS;LkNTtB>1JEhg`?6XwYoA2L5u zgAk-hE7tHpEH3=Ca=YO?(A)YlrDPYRms=EMk!6OW85ukF4a$Z8yhS37|9y+drx_Qk z41%+=$gYl;alNV*Xc)s1LrU-#j7>!Yi|EsjRXrwEJWaQrS~Kv zv#pHJ@E}^9%#tsjzz!7a246S_Wd)|!IBNyKiDGHh*@~{SSK404*oI6*OH@UPsSIAJ zJWM_upLXp78TI)1*lDvjQ1?t)LISFwpdi|T&P4c!RD0~LhP@q4^Y{ImA{|L30ml$C z+YF@j(<$W7^-gQB z%P4D)6)KE~zzj26fL-3qny7*w_hTVU&V010qR`e_#zwNeSJo@U4wLOVdg1c?#TNa^ z%;`MViIX?^?d>E-3)KT*=%nWF=`*?|f#gQ}L|ZWcgC6EnM1Kp^bd8{QxoDV}gzW8> zP_w!fZ&><=$J1!t9Au0P{=Rg=_wsxoK;^cRbhuLdNH;-*=}*dwa@j(AJ<%(CWLglF zoj@c)0{Dm(;SSY75$twuMzq9r?+OmYeo``UUY$-(Ie>#Sd=6hhc_a8;Z8`Ynb6BBV z#6*y0udPT>sC8b4qR!*ne#~WBW>*oPsvmaW6`%UoQ)d;0Xt+!zbajOix56R47U#+H z1$FyK*DKKyP2*qa?A9?;&d?y<%hDw*(o#cyBQP{rXEh5ZljX)7kP#p-balZz2Wnw` zCt#}_tG`xfd)^dBYmi#YXjeM=>#pIYI>rEDGYk=q=8fV;?M0$y}LO<%WGt z&7VrSngW;+qf_1T0@r_-S_@PDHCiQUp6DxyCnF={w3%ZHMx}iGj9SB_YSDd06gsOV2ZTia=F%qLp_q2 z8(HZluH2DSKz3@^l66x-PISSbsm!PrO&IW~qXa#z9eQB%sxgBPhRVnSLa&tJ$DaOY;c%43rOK)`h#;~xqU^S~$f!Z&%dM>6DeG>n(aM#Vc zw4Ghmek8lUFoj~DKc3#CL;!U>HY4lq?@|f7-|mlhYaX(sR$A{IyYEWMobe*8sR^GJ zSjYUYKJd*ucCApndy;$l0EQ{~GfMpSgZW@2ewcQ?0R=(dXrz~>v7ibYi;hiQjFcVA zN26=LqAW*?f+?gosAQTwCxp83rIQt)U6`<%+_R_82Ch$5Wp)1PIg$s!qjnY0 z!Bld}9N;OXCkE5EjZ(^uhxM0wGj&b74j(@H7d6-qZf8o-D?pC|wN_JnyjVq|?>kP3 zX%sObZdRb`ZaQWXQ^Xn=rW|=UtR4VlsUfoBQd{h>tm65C+0A`IkP(PIFb6 zH6pM^FK4^%F~e~opsEsoFOhKdLdfy^0Bs!hh4^tIG7`n-@;m?SapM#k`vCWA(FJxU z;`)jVf|L~tzqW4VnNnyEXNie8b+REgZcjJ{%m+*Lmgnc^68ie-eIGFF6o;GtIE$PJ zuWWKxzpc=4`XoM6!Ta5h&V?j)Nn;Wn)tf%Ow4f*e8>MPe9O@x3nDa0{9F5&XU7hMt z^L$QAjo29IM545L%)x&syMTpnKPifh$`7Yv4Ls+{Y7vcqW5zyJPPf>vV&US#Iy#>5 zvHIM9qE4;VXEqi!CyrRVOp4o)e$UkANxtuZI`u4#y(^CM{Qb<9N5zfzofW>W#O_X@ zI^k!`Hxp~oq4Gy@PZEo#PIYI&RFvW}UxfH1vQWwoHZ1Q3J9Ju`-2{!3@#Dh-ENW8iX|M9pk5Y|8mB>qV0VDoPzp`i~6#`+ip zS58i4J*iav7a}-XjqxWu@XV49@zOEJRo^{3ys%R1yp!`}KB(3>p$Fjbof992w*^Rk zucc6b4jW+`b}E(azjneb!@pA)W0ekkhyL{^ao;Zns<1V+IhuLtXtF4Z%s}=02ok)V zqF>D*(no`~lXhs(W)yEeE%i^MB4+vidy^6O+#q|cpV6nNEK4mg#{{+rN5@qKsjd2r zHx}EFh=S7i46zj8e6(+Iz?0TtoR0>9>Ux_dshf|F$ zl1e_2XOhR3Y934O#G-h{W=DTYGqf9>?Bk2!PnEru%x)yE&2}B?a9IwG$5&WN4-M*j z8&B{9)xd!G_G2;G)^j13oK}#|x83-=$)O4j6~{pBLQR7p2-}x3GCp|4?iwfUU0ScB z&t+?mSik7y-%mU0>o|n|Flfa7HP=aAO&yjUSckc_I<_gu3=@%ac&{))4xY~Yvm*vM zWe*>R%~$vXU^{&^Rx(33Q`#iWE>l0`u^~SKEXr!Zlk!-!hTPTgOgKO<{h@f8(Q&Pv zzA9MI?@>TCTL?a;r=<$amF2Qj|q6PS8X@4I`-s^`a<} z5sXPDuM#VS=@Pqn7is5aO0ogdusXs5!R{eiTJzk=b4GCp^i#&wG>Aw@U%6>^pG6{= znxFZgPFPhlW0sM)Y-eu|^@cH9J^qL^i@FZ6@uk-j$!U zxAQhksUa!>wLk&YDN@9gT&BGN`7V^&VI~SxJqcOu=mt;0SdPt3-hf1WD*UB) z78qt_Vle9{BI#Y0wY8Gw&_FvQKf94BE9A`Ir&EfA+P$k<>BMLL164G2{;B2Yod;bB zUQQB42Wf-`=3s}UbZGe-Hx=f@#yCkq0i;S86Kg`k(i?+J;(t2*)Ay6mg$IsZKS}b2 zv6^FY$H<< zwbEWi*}+|CovFSrcfhSGLXvIfEs&BINLguzHmn<|yCuIsm?d6|<4Ma;d3z;kV$$T+ zd5+7I*Xw-lr>L+5Ex*7j`1QOTVRU?KI|m2MWcrIe{{Hz2hK3}QS%QVlxAD}{=kYl% zoGZ8xZGxBR{Vp9RGDr)IxNIFJ@8|iJ$xO9R?)N z;=Y8e1?CEZ6cwy9@-rt8v+^XAmn+GRhlyP*%#3`P+9KJ~1w5Th>-WTtClDj?vn~I8 zkjp|P+V01#uq`NYoChg~I8vX`-WFtq^d){i=0sH}teKwIiA)TA^!d0di=iV4X6ckp zqF5wW2fj4_kP@7nCkcRZJMdiGn6DLYLd|SDkt}PQq9RZ%6p2)*)9jWG2xuFI!Vadi z6}3;Q9rL|WxgZb04$k8AQ{dQafH|H(Zh;+%pQ|?F=OiNLvm-*lAVXrU{0+NvIA7W9 z(D4EF%fP^ZQFXBO{lqmKmz_MOFyn{$d}q8l<3SzQ@Wv!kn&BAvvLv*!YKcEJPa{<| z@H;g~?wyfM+$u?H%ILGApM>BczwIj$a+1Q6-|lG?A7JnkV#>hZQkTusSn{I$X^2-Z z3t4#&voJ{n_jlBXjvzVjyaA!XbQ0;BJZ``5`ui3lx<($s9t7?_TCS-yY0?GMj=Hz$ zNh@S7;FB2|f_6bNMl1IZD#i6&zz@_Y{LIK8lA_1rI+%!~8<3tPvG`|t{S1Ku@e=eS z=*r5KLdFRm*p$9tMAXgxX9r|<70Q=U#@wa~^r$7y0BbM!z!sKP4sZgM5I#Np71OIX z4V=IOPzwXSBwB!@2gLyD%Q_9%#&H$)@?%W!*$=;S^4~0v_OaSd+iy@}^#Y!{KG;&& z)U0DsJZvjtw*3_IEk!}o)-M`dUN+Dl=%?WfqqE0)>wE8ddwbhtkVRFZ62Ty8?vdO;q2MkpS-?!NE{$Jako%(}?+(&czDkW(mi@GU8P zbBn8`KU*#s0bT0mbWQfJk((Q@rlw}bJY;c^5L4_nPqG<6+7uYZ=KAod{(+3P0SvAP zkC*73Z$&L%qPPr5U#jrE^S>B?1h4E10ub*|sLuyT8JcfYBG5oBHC729_LPQ{Hh7$F}gvo--6M{wGGzc2H~#OjupA=7F~r~JYv{VO?T-J2$nox9#Oa6w{+14A z+CqwjB_Ser8pm4GF0>j1$>=^!jUkLGD9Pv%%s6ecx*}+48zaNi(v}M??Fn)<|nK-J}8R0E!`TqNW#US{>Oy#W4vjsM*kPTI`KCLLO&+c6_m#a%{CQ} zPBqtp#*$!8qyVJWk>=00J!M_JcK5u{rc?m`K6SGp6_*ueg+%*0;E%CzSPYj=SsX4= zKf>__(zh%vIzE?5@szj@jLS(+gdpSgK7&=-*INO^n5M``PhcF$3S#r_ZZ!?&*mVz0 zh5Wa?xMM>k?muAoH=!emDI;~Iz^Q&MLM)=o;vb!>-W!f<6S(62-p^uq2iSSTAx_%t z#Nq3mvNIO7<3;?TxmJwgu(^RZ5gDp0-M$@8jm_P#C(#iQtFxcT;kdFy_AZWuQkmtb z`&`-jfv}4<8oy406%p9O_~lq$W4z_#P#!l>^pDPcU;uFKmnYq@;f*^2OA(Wh@*>@X zIX{u-^|LZOKlP{v+`Z55&;>fKf^U4$jWXnwrGHlrnAdE1+f1+=vj{}szYqq=mwH8o zr2|b@)3SIw_x@388HcM2~y z?Bi&OdW)+oxBjdn_qs5kET{(Zdv7mGy?MU`%lD0qji0yoHS|580cymDEUYRX=0*Yf=HYZ8X0>%o&_@6U7WVs} zZZ{1kyw<^%G+*rw*8>=%RR;c~NM0Hm@ebM4>?Z428T((Q+Hp~P4|m1XAc|rnohgGifFBb5#hDt#)Fz$75f{X;y+n$PwCbW% zStiOL9-$QFYsf~_a&O+cwPCOt@ zt5j98aJp&PCP``{f^tjPpAusvjE3G9nxYkUjL#3@Ol|D!&GF!((&oe6m!D3=F)uYf zWPLZ#Z5n~-Mmk6sq$PikiG$MlI_AsJO3oF1@d5IvBGVB65d5^jP90{iX53=O{6Sfx zzkEtXK-e0S>+-<8K?)^ZEwI96&FR#~@6<|S1meKqkQb#G0a zot>So_BDQXSHBQ3v9hv48_UI#MLa(}piWKSY+ZP}B z4Bgw}Ok8Lb_rZC-2kHwQ_ZM#XCGI?}3Tl?5(~ zX9Z7p6v=2$WVh6Pa4>ZrqdcND=X;D>I}fa+^mH)4<M%k^E?5jgYlKdA@`J zDuTQZv2iTuVUH$3_c3uLq_6Eu(-IWr@uGT z<-JPC)xv9TH^Bl?QsNF7X7hF9GxfDgR9tbWn&u_`qJQp}q5jyo_`%X4eu`YnzWMvo zM;q2fY(z8|o*W>OMEPiD00M@YtHPP007d*Ch+JtLW<$TfXKH9^6*gnoWiU}uK^4ly z;G7D*hqhmE*e54nc*`{ z0qE#rI`pf~J?G3@!UDxhHy0|Ub()AIS^aHYgCN0p-AgX5JFLYNeXM`(N9Q9j@`y9l1 zI$Wpg>TovMiyW?FBSy=al-Y}j6s;rN0b&AVP|<;Wu_AO5OCCCC>7EdQ^Z3Vb>gebw z@@%OZ;=}3^-S5JCB@1{0|3<C|~-X$+0tQZ$^~+wxgDUZnJ7BM-l0GQYPEI=^t$bg#EO$ZBW; zr747nAn@+AE<~YUa1;-bF5Yv>yRE7_UnGlQ`$_(5 z8M83#YVbH9Uudhio_(n4`;xmW1Ui_8Ysf43)OjaqhKC-UP(pb#Gp323jN$Cr@~txu z!vI;n&OLx}fxT|a6qEZCF$zy8QOhM08ymVEm*Xs?Bo0W#TYG!M#WPnLyEL?ENvVT# zA@?e;u?)utP}vx8g{$E}oDMnM%5fCOSrT+ApzXY=&XM^clMR7n5>HbV@g`oVHi)Ef zqFhk*v(G~b^gL*OkF$m_XPOB5X$=2o?=4jMeFluQ_Jn^_j9yVwxGzQJwFsF0;R5wG^yTwTq zs@5tN6Z1)KsJUpMI#3BX za25=YQl+iQ+>?H%W~gc6$06+K*Q=4-I!pquuHi;hnry)WVD`k;n-M2kfN*F;1d{6~ z-M1|d`&;3ZVNs}NK0qLfgZ*JXA}{ZP9tOAYZ~W_~2UH5j4g`GSQ#irtTLa;!{+^8E z;Y7TeW~}|G&<NuGlhwf9uadkdT;GA%Qzw$fg)TOk)N5RDGanXUA zYR~*NAPtK!MN!!*3q(k*AT=?ejB!Swv+Ia=0NN)eCZ@L8L(?uVi~bN~V~e3b)Cj$@ z_?mjT11+7lWyz~l=N5#Ji3WH-7RlQMQ~eG|`Mhgfh6-auAW>QTRS3+X03{@b0laln zVNgSlz_q@2+fR1JVQ%zrdZ-$vauOatvs|+`!&V@y{ z))bxZ;|33J{{#R-7_NOUP^;jzT|i1(TwY#A=0E3Cu^ft)R8&Onm+}JjCHYA2&$OR0 z;1#!S3CJ*11!|<|(r(4r2n>Cp)iqgX!6|&BC&_$<>llSL`@G8-kpQfQ~GeEZj9TG>l1K-3y(_xFec|i)@$fc89S<5V$hxFy6F4 zSvk2Ut{pbq%+`B1g0=aQ$hrE!yAo@wP{^G+9_s~#9gH~d7& zbahS8wL38e#j}TFonr#;j6OEH9mRkT_~M%%6DkmpIkEx|BdEc-@6iqB>FGM%Ng6`M zz?5$I5gf_VcMx;PR0H%o4l3$rGUM$oEUkGy2n2tb`g!dc$#sFs!+?1kbD7#2-Ut`g zijhK2^CnRLAtM_~Em-~ ztvEi3+>x~T16T6$f%e0@fzu+slB8|5)qXQyow_LKE-bcV)e1!Z`92f~ko)jpv+8XW z&DxYck>EGKf&VSyNA%gTGg{1d<=XK&U%%azna_R&QjGok_8gG<98`ReE8DpJ^bXK1 z4Z9<99aE(JJz8wd(6wPk3?|0J#I%sd&2$Dus89Y?) zF%U3(&7?j4j?a z4&h2Sr&#bG+VE^IWFN1#VxIN9bZc}q`7GNi7#>?_8z^xAy2AretBm`>ZjB&u4r7{? z+dsSG7ia!2My}sd;Xn1pzsWbxqs1VK8B<@qy#;?Oz$gE<(cXDEDLgb)>vTBGX4LY^ zI?5S%Z-o-Zr&!!NR{h2N76f5brS7;pI9bWvSfjYuXzSZ3ThXA_l<0(!Y{Vq_D^}-W z@o;^zO}SJ6CmC&p3{*4?b7{!JLofbzNzqE2lgP-l@vVy62n#=a z0U^cktj1JdaqgBpMx7Z&_uX$&pX=q1iAR#b`BupAuslS6rl*aAsRMa?o^6_}VjYoN z2Tt{im;b^ZSE2Yum@skzA@xJ6X{||zuE5(c6ILn)@>^f>8WXnu*@Unx+``ocr|{|U zG>x9gR#b*AF&JbmG*RUAlxeEB-B^^VLgu6Vu$#8(v?OC>hY^c<-c)VKJovTj{g>r# zNOzwEKwWOcwisL^tn%6*wje@G>8tqE_pTDk*6=iDVsR|harN{xCoh+H)-{5C~BgAll$JgzULVZ4@W>7U7H(& z0xn+#Sqw-h?6*4zTn{&Ah!2IVT%HyQgzkLNEm!-6aWs5<3!9%N4*tNrG3!Rz@LRi% zD6w}}yrZvrDJS@=gjT)D)x{C?bLGuET`(6GY?<>I*4-5AdBk72?W$>fm^so?hrG8kZM4ojux;#47l{LF zB73e8*hc>Aomxm=9#~++&C{&@ytQ>u+ET*-vg4{bT|yCz}VlA^PUf~B07xq4W)rwWj`j>=%}vo|<;rZSQ#2!Ej6 z!N&VxNRF%$;BDi8aUR6YAM|8xNNq7k;pqk>Mb#qVL9;*tKNN!uee2)Im&~1QxedNV z-=VNvJVt!G0@;+G~7+}EIl**ZSkXJE(K>V_bom7^@Aoq=KH3c2U_#Kfcm7)<2Zu?E~_ z$V9!G4D7AAi60*yS2}O&-{S(|m$h!-Y$?dhzEwXhHI+tW4nb`yi7%ASq`ib7Lpu6l z0Y`?R5*zO*_Pm=vKGBs#nC#x-J5DLV4e5No`7&4MbrP?s89!W~bDkf|D2o5{3@-NM zV!hwiXP?ir(6z$?{qmKD@P?EF{mxUR-{;m5_$wB$TVrPCd(0 zs)GR&D$;C{N=Om@MPCgfW{y7ZAJ>Y^wK}(OJAiw$<;NimH_ox|a48CYS8r6c44r5P z?K^8!B`PWkkC-L!nI?_7sAOFkYhdq40#=j~psDssErAYd6l=g?T18RuTVX@}c|mPv zhMzVrF7CyLV?n>JvB5-lFmm)~>8oI8fpvh$U4v(zTr=9}n8TWO@?S%Y(3*ouFA}$Embg2qVPRU=}FQLXULR=&cQ z^{^+3$Rfsf2?wHBM%%k1AS{=fscdF$H&a2Hjc&M&RyiuVJ^j_Gh`*BCuI@^WVk&ll z1ha~fj;mqmC8#-nTLdL0gqYc5LvNDqY3S(S#GkITD$Q_~bjbPmlx@2s0Ht&e`RCp| z1vJWyJTsEp114fn#=7bEh0fdi`yi7)BX67e!55(<%ayEk*QKmX-{1s1|4PkW!eWh; zSQr-He;POZ=usr15w(;yHLyDwfUf;JTlNosn!36d>S1PU=-}`qCh!`@OS2(3xJ!LD z>PRw_M1yUly*m8)`R@*qoAFiaVdi)bx920l#OvKWVYk)DhSZ1;06O)M3f_#3-Mbu8SGa@_r=6j%_%j1}WDM*Sf=dbBzO$I$lz0zw91)(P|e?(ny!ps2OmVr9*MZsMp)zI&#eCT=FFZ$;##aR8SvQfT|7+nl$V#E z`1&^dNM#gAws%3(|LOPe-fu6O#iUMLuq6PzVFDX0kyc+6AN3o5p;3H&-H=6h4|z{J z@d?+OftL606*@dAQ>)$QQMlSXq3cm6H+xljEmq8nIzQ-%pUj<~MQX5vvu9x|IxiKT zw^(-UWk8^%jC4ZP!lg>e?c9&HAeMx9A7YyXThJULE7spu)Lz(0aLzpLpQyBi7MB?gH?2cnPH4y|-K8gTk2hV~ z$pA~hq=|o{7Rtlu@iPi+lJ1=-LG{j*h+gO02yP4}p$_{NtXU4h6n~^Lo>}3k|7*Fm zwN=;Jy7vd4`=9j8ZZbcC^uN+`G91_OFYDO3bsDbj!=n-7F9^2Fr$vtRX&|G5Qu!Zw-npB48XniUw~a-X#s3Hl3-q z2fz|`^x7wr#TKV&h^X%Ln-ai}mrKlKC@~56qBeAkZoN2(LniA(A14iS!g#sDWI*q{ zK{N42OaiX3PVxM!*;eN+S2i=G&Ted)xT>J}GZN29%E%r0zzG@nM3)+Adt3CEXI zVAquY`e60~R8V?X5~CVQN9vMf0vm1=B$`YRConK@f8FF~4T~@AQ$oX~e%n=#fVy#y zmQCcDxiYyhk=9dKuSXfH*Qx>OsS4Ix$mc%0cV_f%n`f42vtMkXfUgliRz4woAlDSXZ) z(MUhs(wDbWm7LGPi{Q0Vq-if&07SLzx)+`c#g5ZSIP#8B`)7{zyD7D@Z(h<+U$1T` z0ZH?#M91!*xhs7oVD3t;Jxy(F5qlZgqr-`y^uMP&KzWbsgBef84w^D~i< z>!-}4_f6I)o#({3-6iCRvhGoV1@+5W5+}_v6eZ@-m9;oPK0_ytwzqYofl|xfu zhYk)|iMlpjsHc8o<}@ua)0vozmZXBjN1=?4JA5x_&xz(X-gNzgsBV?nKN^FfR5DTl zj9s_(8IAhw*yhih)TUG|Yt7z%{IaUUu;^SwTAFP|4XoLvD(P^Ht=0{{ffQD~tCr+! zt^xC~CyRuPRLXe{Zj8;pQ_tc5VMN~;^PbFGP80D}CtvMZgEM#+-q_~_=HyQB{J8w5 z-R%fYKNc0@%-V zk`l56+T7|H{`Fw+$kA*S<@0j!o`9w_M#lL#cV#Y6J`CVg)ak;)Kk~Fn1~9110=Prf zw_Lw=xCDz7r_)t0+j1VkG9G4gViav{cWIk;R1m?Cv+!NYi8)9wluX#YYMxwq#c&M} z;8;{J?^mDn$9eeNla<7h7Z8FF+HVG^IvhMMN3!bngOMicXG<#&sDD4Kg(5wy3Mo^F zVu^RYq#Fo*1(?PE8YYCOg_KtC&JqsZRMM=p(kZ{3UW`Ij_w*Z#9ZLCOC%OAcgjbx6w?lleewb` z3w$QIR1G7e)ry3Lg#}OAE;(+9u~0qb znNJJh2Bl!!yJlYFpNPK(_4YPn>fgu|!h;;NEeG~CEHBh{1xh;MZHN7ka(L0B%>MLI z8nkRJ;lZD4F~pD-VQ|PF1%nxX`bBc8&GuXn*WWo6@-FcXpl$g9}YB>U*rP3WVneaSVCgDNsI~J3jJdb$|L+PVp z!2A=z#)}Vu4mZC~%QJoFQY}5ibzsu}3Dy7B6yAGkD_wj6Vc7j8);=X*(UPNJQ^zCO z{t*q+M>Ce>D;chwz~+6qGnqOJY^i8OkcaONqo^xjdhQW`+SAnd7Sg-veeP>$uSq49 zQ8)I%*{=mM?2oy3^3P=rY%9lfn+*-z7F=~(3F!+$m|2%JV>!@#$F&GMsz`o6$h$IS zOg}t}QhaUHW+S*Z9iA!kr*3H@{qX!$JCgN2{D|?-`Q$=lKnLb}x*KYg)S`KH1;6Pn z70FrjJ_3{f@UP2Oi!?h<&6&cBwp3mLfU#SLy;uD++d%8DG%?-6juN`vvUF;WF>(4~ z+D$)I-`jq-wxWXjp1Y&PuJuvyzZ&;HruTFmY1Zestf65|T?`1HzSS-6s$p76r{j*f zzeMvdkjwmzP%5)-h_W7gc|sQ+AZp^-$kuN8f=_XKqo|!vir{rU085KV>$w6aBDMg% zP|Cd}?8uMtDWw%tO#g*sooMMkJO-<9=^Q6F)_P#9>zH4QKYnFM&Emh~q(ET$pK;O~ z=U(%(pw*wd2vX6ppU2lpdM`q_aUC1|VgA(v!-E0rU<=Gn*KMc;AAhWk z7e7t?8)w*s^gm-tOM-lu-Iv6WtG>z?B)PiI^2vqsYtkS|!-YXWV{sw>VHY@X4sA4nh5g-bWK9*Rk=)r2V;|FOLGPbW+{1E3DMR1^%4=lurj{Uj0`$a4Q-;_8vFn zplDD-@ivnk{8cw*>ZKVI-f7^mN3|bTG+?Z{l5@W+DPT_-ugbMw7+|V3=FzoGzYu?Q z$?iR!ta*Gd?tV=gHH>J})0|n7bbBWbu=m!>2Ho_Jc(x8e7eO_o-7TAT@>%oR6oW{F z>i0bd>E=^fumHRugR*<@_;S+7n-2;2=3}h>gOlG{0nMkul_Tvlat% zmjs8*`j6XfVQh1DQGfY58|$%zqjcKX(*_nDdDcCx8Ge6?fbitt4zSmWe7nFGBcBb! z_k9|gY&ZPhGq^RPURJ4*Gtvssu_)T*j@wys!MQq%SYjUR#wI3$hK}};ucoxZkOM$w zL#05XY{u(9)+LJ7Rih&VK{vB9*-IUO#ws~Abvr?xLNbm*2qSk|%hvbl`XZ6ubF7a- zbuBZ?!A=u?M1a}c6ux54rm9wBD`iPPNi6-p4_@&`=duS7iPEnO&7g@jMS6Prk&%&r zxH!xbwOsagzxI3kn^5$r8VhWrHi-d|b!+^l&>X%Ry>)3K9W|E?aUuwu<*m&8Lp zDSlZkg-JQg)Zq#ihl0Y_dHuftw->tP1R^h;qa?42KuhjD8ep>cq$@1_k4qZY@2~h$ zmVEx_biYNI960w1gD!Ma9ezeFsd4u%4A_}HB8ebka*pV0fi2(x_-YFn>QFaGRn+S# z_NhlvGaN^2ktS9QysqkPKeCY#BeZW|c%9!(pZI4K*}IlHteNINbx@nch1KEFzWt(D zi4;&f;<5X67PZGh2tQI;b)p&@8>1bj0}L_%N_%-)mh07;!i*5Li^=Kr&@(V>e}4{} z@5_tSWcdFaH)ewd*=X~hpKtJQn=9g%0F*XR1vPlaTR`Dnx4QN7Xl^oj6!~-NU8PQ` ziQN?$FnW1!Ktb2YD01ke;W0F%C$ zxm9u_q|C3CCwQdl**j!VmCd))`n4RLl7jmH$rA&g>kdqJGv42v#eM!Y)CcfqR3ASf zb5;G=8BGFs+QkoF09g!u0a~`izjMeAs=$o$m@4Xm{MaNdgLNfVf<=Vvd!U2}D)*D- z9BSMUjhd`08!rc9*jKa2?4C5x$7jWSKQY*|fuGnUKf85St1g#U2sk)6&`9}|&klYb zE!GmU_t|}2YB_?2y{fGSbe}if3B}hyGx4f&JfjD6pzljViApwiD{ZRAMuxr3PJS~o zeN?i;c3gsm<(z9r;dfl0v&|+S8VnekoyFzj=hdAPa zF?BpE1H`Z_`nb_IGG_99DKOaYi2ErnOZqK)fxUGB3~KT|XoV6YT?PI#0nYocR8~OI8Y8#U^MWQaGScbs_Oo%j715`9h4CNx(tYks z*+3!i(Uws;9qL-%2ypowI;#>B)_+8?-vhsMne$ZJeKdX?t8UC7D)9SNdRT8c?6lPn z53S5@);%#;SM!(agcvke;aoK~3d{hY*nAaz^c|vgNPfE$1Y)t;wW9rYE27Pfc#C-o zFPnfct)?PNMJPL}Ag}ov7sE2e0lxI#8FV10TIuNE6V25zmsaZ4lC04XG+XQq*ST0_ zl(?gEW!TV_e$4;j%Yri`C~c}01Uc!E6tv+>?A%eu`#{tFgP{H`0~Ih2{q0Lfy!ubn z3pg&h2X%RNg;#a&_nx!efWB&MAv6sjCH-8c`PAyTfgqfHvp-!3^W$f`+yB$Zc}F$1 zZEIY*24aFpi-0r(qHu^5#XzKlCLl#h5J3pNDbkxrmy19s7Ro_7Qi2reML+@R2uN>6 z5Ks_MktPS<+HkJd_wIP(-hY!Z_TFo*xz}EE&F}kZlqWh>vCt&N9KyV?-Qbm-fE{6G zp*R}M@LTtL;@Q5x8h@kE-mCUHra41xBcIeIpG3-wLPfSjY$W&U9t`B^pnTuKKn8#V zuITPqh2vvnDh3_RDM5cVSF`47d4mekKk}}McifrbUY;220xWIp9+F<#?cV#5o+O>9 zlzX(B;kn0JIA+CCb3rPC$+NA>rV261LhV2H_!vJ%Q^wQsJ23nSo}GIbU*FJ>p(DJu zRNRa?XG={@i9(nT3|7wFNp8=FEKF zl0Vo;a}Fvfl@`$TbT7+Nbi`}^BF8#sL3PU?$DV9zV}myH`M^p!{;pEbT9+AT z_JS+lO<=s!cXNSBvNAQ67Q-hYfGqsH(!q9bD&Mg)_Rj}ym{c>Q zwLFE4WttirrC_Xv5jkNE;hWY%?J`2vEbrMw6;C2a(k5NgT{#+$iG#UX&hySmKr6|s zQa;FWEs(cOCue;DRLxnIS0nnpB1}!Rmq3%&dx<8!ilM8zOB7NR2l5{ z_96DF>5Ps)6`%2nvao)8*($AusluYBVy-OM@9uf;&M4{h2J;WNP}`s@KR%pw^poDS z4xr*u%1ka5O`Bj2jKjxX2#4_+9QpL|(!&_@{8~q?~BFA-}|Vgd^*aj)RrU>T2|8Q`{Pbn^N;M zI{Ti6F0Zs3c5ip3E>jEiytsY>?U^zVU-3mSe-J00OL1s=W5^I`81XU5PvVW&T!7_$ zA0sk>ua?Ekn?h%$EN4%s`80z}H3+^OZ82u@p)6kDf}J$+H7t!h*>tcS1F^)7A( ziN>%eKroG#t^0ZPAYO9=NlE{-)q-8fjg#QJQ5zm{%gPsaT_3IQCdHMPb;=d>M}Q#|cvLlJM_TG359#}p zYQUGuXxKC=g#n_jEzkkPS48~^ZAb=3h5N!Oc|f9h4ub3drIkIbC__wa{HR60+0V#K zOG2X!+>oOd+o4xQ__p-K@22`4S0P2u8~8=C_%*Cx#`(-aiM4eJ#&_qsyUfpkR`J$+ z%B{6A+caR^w1z+@|BP|ET2!JLGVSq>R=o{SqO#sBwJ~DkNdCDbhaDQfJT*q-8$<_TtA+J?`y> z8irY?1u)$kStMNK=qMp16Z4eBM%<2k_;QGbUg)YBRvszfP6I3i)1x+RznM6jlc)Im zDvh2OGPIx}iF_%}(j_36BP3@a1=xT|F}dL!(JCSB?P?UnM8q2)g*Ifh<#Y4&(rbRv zFpA^}e?|nQw2+dchO>NBZ7ywx3`3m39ae`Vn%z6QNNi`t9*R2pSkjmbA*cHALoy~d z;&i1e%bDtMk^gIBY)dtzH3(|?ZrtvHg5B_tDeEib^Wq4#yLe zu~kL+g|94UaxHe}7{clj+#3*1rE+yQ&Hvi@uF`;j76-JS!7onERV7VJ(MHe$gj5z_ zzf%Mzn&RrIJI9_N^wse=LSu(l#WW_gr!Ll6f)?{4gtr(MIrqxIg%f+CBWqbVF(oEU zb*TF8vUli2VQJR8^Gm%!RoM8DrP{r2NrgeEow3JVX)l z?Vs&m4twcYn%orgvM8kd=`*(Y z9Y4$JTBbr*?Tq?fwuF^UrHCHo>^Yuhs_hHpG&wHURv!FHUf{xLM}%j7>!W2Zr$KK^ z;}&mkX;T&fY}Dc^V_+#C;Z(Vs1RGn&7vB~p+Vj`n^(gJc+zgo__L!TBJ+7*4O>RK2 z2wgcY7xq?P0!pid1|^Ws*bLOI)uA+Wx9Wjvz4;#_U z-kKOuigKVe4Bu{Mk-xoSBYWd5V{u<9?DeF6eTGYGotuzAtf@O0cv{;`+dU93AITp^ zCW!7{@HGj*-(uJ!`%+mD-UFyXwP(XXOT0PJZ1>y4=#*nndQ_PYyRRuz2qSyW)7;E=1^Z zbvEtJSQFMqnL?%Uys)yXU&hsK>wi38*pQ|V10izb7DQY!m^N3nc`82=i_MB%;kCd63r`eccsd0$_g^@EaPvMEkZc=bj;Cw$~n?*1ZoIl#48DhEe zzif)s>ioPaXidhkcQx;LEuuAVCoD*kT1rX=Ae&>xz%Yv4k$cUzMKbyFv2DOP1FM-k z=hT?J_#8T?qxS?~$^3}w_*r9Wg2{^e!0BodlcIh?l2}qb!r!?7HQd6ayj-miJHn;> zwU{-QlqyPQ&A)dDj*jLgA%9$(awIyC1f-?dVeB_rc1D#v<~ia?h6>X*f;OmNhXAFw z!?Uq))LmOGP1hv)W(g(cCA~)U{EB-#Kud%Q$HNt=cf~sj=qF%bOJ~cT534byD>}4o z5(0P@S5ScuI3*tnZonbx5c876#cz;N4SeMiAcT`BC-GV3q7eg$Q;pF*{F-ra_Mai` zxVx+ljtpCVJA9tkXIHXOR`XVtKoB&gz8B-LTx3^PxDcZSkG#LZSDMZRi-yZinett7 zqo%tOq{ir~?AaxS(c%|uJ_i@ko);)hrww~775m*)rDW9`kEpyyw(yG2K+c+&1kIWL zh%+{2Y&T_I_GY!WMp?kM^|h8>t%xv6U{;Mzt)v|f!fV$Sm@F4+AME%*b#*#-0>WP1 zDzMR;*b<(2#_4HmacVQs` zRs{t0(%gQ}C~H48CFmQktJgGeoZ$5rnm^62*J>z}#m_`-g7Z>A?pLv7S4!5|12&hWo>i|&k@bR05u4OBE^+-`2)d9DGPVNB8oe)Wz_Tsr3CXpnh!CkA00fZyejTS# zmIX2By3OlBunJU)gTA+n^l-KZ-~N3FQo*ePy=o z+R1MK@=@d0A_;(l9@!rSMFEpTUF@-j(a0gjV4nUFuYRQ0$o_Ii-gHB|^!RZ*j3tWP4Yi?D9HqBo$XA|&j=7Rw|GMFQP zM+3Y{q9Cl=hF}U0M&$-y=iYuyzyJR&K#5c@2gP$589dV8Ow3>0$p3`8RMWNxK~d8H zz)b+h{C9{V1gva~ktJz4&#p>C0>lSUQ82%g166k6X|F3w@Fxubgi-Y&^lKgvu`U&> zXsnA;vg}oNAMHoL2U||a0Ie8%?0cZ|^ToaBe+z2>;KYMb{<@ML!0%lH*GVHot-*b= z&OB-n`}Gev6zkn-6|noTQwKayu+AKCQ~+=jnp|K@+T`bEvuk=MAPQig?ocTH1)JO_ ze*P=(0P*wx%{y)%o|N&n8E2^De;P{jp6?nEe2M82$=Tu`xB~y|9FXDQS6xtWKzfix ilb67kv?aRzbM42Tz}@I4l7PZ`NL~2~{+XhA@c#f+Cwi9v literal 0 HcmV?d00001 diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/switch-node.png b/ui-ngx/src/assets/help/images/rulenode/examples/switch-node.png new file mode 100644 index 0000000000000000000000000000000000000000..88739a72e5a146fae6c3d959e921b1b3ef542c37 GIT binary patch literal 37494 zcmb5VWmH_vwl)d`>EQ0xcnCCZ2@u=~ZlQ6vV8JE0yL*7(7Tn#P;1Gga2<}e4Mc%#l zIcI$5-f{0Qpa;EbRn?qT^N|^<_+AnXnHU)c1_n)9N=z9B1}+%}1{MW`2z(MjS*6P8;}@Ib}4zUMvy3TN%$sCxj3M%t`5Qm=_sAG6pn^M zc5@Yyu`Saf0lkm!AL-EP*_4gr4Hc)DMY)SfsH?DnKVmI)qpagFqU2B(X(*V`OyYGy zpxE|12Dw4(-wS?A;Gjh7z9?F~S(6GUdq+A%cWWSh4*cH`UH+!jR$OcKRJnvKI9*vDu+?P$`sf~gntJ~4$tv6~V;a&0wj`4M56 z`FBfY$wr+36MI1yiz~PK}QQs!Xd{YEWI?@8((P( z1kXyE^n@s*X~$T||;^W&ahi#k@8D)~R_PZQUTAwe}xS_S;_&jW!O zd-D<@mmSKJnyW$ztVK0j=QL*E+CmBTeyo-bXic*{6WcR5I_ei%h2`*B z&0Z`{6$`FB+9x-fZ}>GMn`@;2KfOY+2COKS*+0A7{NHz(W`b7I^UDtO?AIisc4cu8zW_Wk7lwUHHMZpJHCDCp%Vy_8M%8}B&B(vIJogdUWrv}B zj}Ry^z64b=>8V$m<4~Gf>4~K+ho&>f&H@$ikXka}A;br*9u(opOkf9#!H;{^O9DaN zXBH4pkflnbt|iI40E^atg|3`zqJ0?+rvr>2sy6fMa& zg2N;=Px?v3AZW8nwUj5qR~F15Ps`O-d|>c|{|xT*ZpYcPjmS~n_yISbP9z(Ry0RSV zpFQs%3MDRyHm} z^qZbM3xk=gAU*kNcwS4w3`(q}N=_dW#QK@etIWE^Q=ygKGw zwA4Z#h;zjw)N`6xS??>6v>$?Sz)9*_T&|#yddwuY1;BNOhgCH98KWN>8h$(FfOD^HVF(FWAZ--X)`pYqQ%O7 zR3sL{ij{rg^Ff0a7zm~yFaskh(*(R5jPC}~elar6s^DztP%P8i`XWDt$Be2q(p3vL zR#sPvSOg$E*@5?MBlYMk@=h7f$XV4R zl06>J%(H>&IQ&u322F6bYno{@SN!qv@$IH?sib%O$aE7mt5}eb zk#O=%cSN;b`M3GM6)8i(%8Uuj^GIZEAP!SxA!tlJt2rOf3kCMqBmIBwZ#aK)xvz;? z3jGpI)65n%)fJQK`xVV~V|4jRya0-J^!s9OP;4Rfr)vcBAO(rW8idhE##p;M7^-1X ztaUD2WO;6?jd9V<-@$foDIpO2w_BT7dy5zjPH)tE=|ql*Lhz8OvvYQu~qYh=oIF*w^P1iX0d1x`cxN;TUY4oz|v zf!77iJxg+ksdtPbSGqygpVV4RN=888vcd(otYWUw0r9cOllH;(%^fVcItahzq^W=i zrG=wYYvqtjQ)Zi#%o@xWEV7so{qIpqzNM^_5Dj&E$2;pj%_-I94Er{r;Kbg^*USbg zOY2~Z2RHZF*{Gu;9q)k*`?4SeWothw3G;U zZ{ZE9*wJnxFv3!PgYD5~Q{tQ~H>M9snC~oI@PV4r9f*efKma}mt2VJ?ymqD)S-%%^ zQFG!{WS=NVeF*(|g;JTt{Q|t>G{PEKl6pqeggW4Qa9LZTJTkc5o_+gA+2iCPtL>c=nji`gtN|rWPbCjXxz)M~GWz7omqYl=n(6e2QZDt2MBsLbBH}+`9DbjP?_kdx8cUUq>mT=#s9JiNFf`G8f?G>T$yck!^d(AuU?4(SdEL9y zl(;xQ$;HJ5=U|xSEIJ%=kbHvX+8bBi~-RUy9azE9VgLSfitpzw9TK zrArMyDJRfh8FbW|v%VFB^re50rF~5<(Ea&%1;vGhC4z+K{l2UIW?NAaXsO<&XFT(* zfiaE1aQI-p^5T~9^wfLnlrQ*iy+i7E``!~E&v5I2Lhm#C(|I#`rRvPmQ9&Tg6-Cot zWjSTtmLRVEIfIEZA+`-`3<3}IUc+TF>egRuXjte4gJb-Gl^i@uMdG3uD3SpRUa;c~ zy+2+AS6w%dpQLUCS3Z5fw{zZcSk)@ZXaiyFG z!?3YDc_}_->4MY;VV%fxKfmgsX#iigm5J|S;c7(ewd0u8b(9(i{#u>6yB)CIpvd>k~_g<8Y} z4Lr0u&qV_d(3b+mFl5f#uo_hO;GVx#yTod4bTl zDo%Pi6h0n?P^g0+06TDE4qdYz?pOarHLQATvrx`?Rl>!#|H-FjS;CI)YJQ8a`DU8H zyPI#&QEIM_8CDbRv@41&N$O1l(#X{7bq*8!?z??8wP7((hzKR;5$n^#5Ph!kKC;*C zb}|S9BRL_uzRyA%8rQ{1E4TFNFFKlI`={Vu$g*+xJyX2UX#Z7LhzZ(=Ij}P}D-DUJ zh4vFgBKR%v4FEy$CZ*uA%!FF}v7gfUH>LSUovxkHRo1~FGT)@B7xWjFq$a-;K(3Ou z(^mYIRdzQg2GS{5&**7LKLqOFTdGAX2D#Oj+XB!PaMi69@kjfJ5;5S%_YI?Ycm}Js zWr+fHDgsbW!NrW!>5O(#cmZXaz6=T<1?kec2m}$9*!C|<+?3~$kn29l8bQ3Iba+)^ zB=x(PQs^(5>-id(ff8}?@eKtb0y9u8b^?Q=OHw6o*ijXa`@%d!6DSjKkV04i@bLnG zDp3F^z(v}5d)(?D6N72rjg~j(bplJ}RVXtenFw?p*^<|p zO?e#2ai|5a3_d&~CIF{I000APpgB83}qIgs-Awm)dimjb>5a>nw^#<1w#{nHrPS1LoVKJ#1MpZ%Boy zx3^&X|B+eTJKjVJ|5sns1qqE%etf^Yy*v zDx-n05k=<2)_3^V=VvEr=TeimocVj2Sjj$LM*2+mkki39SbPO~)4~F2OaX_y!J}`E z<4}H-ex1VGG)1it=w{6S9pb1$_wqoSg6VVc~y@b1$($Ax67-^pun zJ7Pg{;kk$=;;tW4$YG`wWCW4W{g*3m0{0}5*Y|KjDtCk}+ujHS#=$usc1`txE6L05 zsV>ubY>_vE+gKo6vCoKD*+!z2pLy#!M`B!}F_M5_va`13zFo5I0E5A>78Vw+7r$ap zf|n{E4`d zB+oxa9S5!6#YtYS>>kz_=s_dSE65TTQx;5M4UEr3nAzit@qnj{YddYbB*bPy>aJm@ z7&tPg+_&+^{C0X`9K4&LrKz+V=OS;x&Hbe%qLGS=lihJ$Ygp04aS;BS z*_*P(rP*O?nq*k+M;*+K?5>pnT$)GqmyV@i(4{-<#{%MBvK9Z&i60E&9(ZVQtLP!+ zYdoe*e)k#%xy^|oA@EnI`G^iR-XLNQeBUJY>}FE84)5={+oDGY!FA|~A+l0J7m-xB z>cm|Ie^>*eh|u>*>{HIqGk=U%5ebq_hH=7^j`~gK@qx_Da5xu1OHRa1=qv`o+I&>? z6g?I-y9Rnm(W)FS2Y5#`Ho1_gmdE1lBF_sD#~)i3UBY*;oBffZs{pq#8)y><{M2?; z@w~q}oaz^;+L5%zwMP zK8~K5nQ>?TDiPUzxj&D^`u+WsdLtwxk!RfKJd(ZZ1&I1Jyc>F8e1gZ6)!;Uztypwb ziPyY#&kD=C1m859)8?(Iy*aJXw+>|N+8O~1=^}2-So>#32C8HZxACzEa6f|#aL+Kk zj@~37vm9JjTbz7!b=t3um6Zom8DUV5n^TJXv<8pJiy1c~whMZL5^0gOe_MukfrutC z8l8w@_xfDTrwD{Uin7%*ky(9if4O*)jCsiTjVf7&ufQWp*hh=+>dV`}w*1GF>(0;< zb$Y5BA>^4y9jp!gu+ol<0d%!@p4hzPS-(rlJ=CIiv3R=?zn0lh$_n_Hq_V@iHW^?$ zV7gJE$-K2aaN0*RIdX&l@+x47S1*8ZRA1L!m%fQ#b&(`K18Gxy#QP-Cgi|N^YNrq3 zq%htLe#+d^GVHZR#Y`GI35qpI1{rN^GoG#sKPGUh7h8GbUcQZ$Rbmarw%kW)Dw5y? zi`iJcbXPcYzB*M`RfWIWVY}}M$zSMgP3{TC_(rd56pw|4bpuTCKA(72Er6^&Wb3S= zl8BQ$Hj8@-BL9sp`5n(>Cqd~1bdENew+&^)vHWDHEcC=!to{Po&nWJ<8{`Z8h3Y%K zmm1bzxK;0yn(-Zq+wDnV>5n@-hEW49dEgk&vD(8CkZ<+BiAJq8smi4Ug5FYRGoj?P zObGKOxWO+bo(6{ebRx7*(p@;V2{ej;mIND4qY^A|AZ?V_fZoKR?Mm0M3b;@tE&qz_ zm`Fpll~@a?DcG}1<3xGA713KD$_7#7bzyYnlMT-G~lg402GGxCGrIA8Y+3GuMzYd*!dwprM#8WrkAa7m59#odS2v7)ys#%gvw@thO(% z5VcpJ=#H275?fPbC5Xo5ZVp;O3oksXny2uV9(&_uO)MX6c8KL#7F`WG9Kk!Yw8^tJ zipW_q5|Hpp=Lv9cnulSBONYc3c8S>N(igaM`=^s8EdS5jJVzE?C|0S;UwYXMhwFdi zDBG14;rS)<(=H;|66E2CZ&*cY*4FAVkdU;Xq=pX$^I#jQK z!xDuiP*0ZFD)+P>X*umwU0InbMp}X~wXixrG_%e)xuoGuleKi;C9k8_cGE$yf@vhd zdeclaw1gv?YE6!lE{$Q4X+Hrcr#;3)F*aH=KgV@3Z(rM@Qwn z(O@ufap7f0`mc8he>yJ4ss9p&WR^B0Zr8I=rerpaw)%`MUazU{j&8@>*gp=^mVDh* zNJke7Ij3Y$4Ev(&Na=Vb5^~_+HANo;-AOn68P1~L+=?0u(d|?)Ie>19H5NnkS8_ge zn$q}@F@ae|dRDB6<*vz5CaQzBlmo}^(G4ZHVVKA`Ks&#!#pt1uNm`d)x!nlYTC5ar z@WJShYfK{&zp~(sKcI^)fKZAYSd47k*+v5o?|=Jbz1dR!YFz+1oUniS?-`3go@ZPe z6AmMt2U^UN$_{~wKx{Kn?z4jAo%iSD7vRjYWSuLNzhZS8UdZ6%usrk{0dKTKbjg@?J?e3Mntvg8D-=>nqorssb!){3 zivAYXYb6KMZYD&=fTO{lIki> zlOv2@KGIPoBliEXkV_+T6V9%$`>8)fryT{J7NX$ywDTm+l2tbygF5_q@>;h9<4+D( z;7!rXr?MlwfB*h48v1)$)AT+~X3%8zeh>g;pIA}CUiyYqT3OvU%xYlGzWg;=Gn63z zZ?Yx>IDkSdk_(^NI|UE$?mY5gntAJ~a3ehL((6EdEB&IAV4dIMQvl0eC zD95B*%3gRmNDkR{WTDapCO3N<2nQP4Yi&gF>q|TJwxQ6oRIEHJu)`}d4rxB~s(5&f z`0h-DD(Y|6BQ}Bk+9PZSzjU?mTYIuHWEB)_lT_2v(~UNIL%aEgnYHUVn`~B8DHY@u zYWHmHy+-quBc};iDDNZ$tA~A8+U~)FHcW8kOKJ0QTu}hSq%%ql@QLIM++Y3i-wMJ2 z+@(K2vEQysaSvgP%%#vTZtoJX=)$)gv^E_c3wqskE-#Z^T^*?Rmejf&>w>GH+Lnwl zg*|by-plXP-mv~R8<42Dv;&9$pN^qV-A)%9+=b1g+oZ8vjV~ImtJRiAs(mrh>5nE8f|6qk%8m6H7bvciQ ze8#6*ugi?ZSo;>>hidiU6Vift6>mZ3{;R+{7k%8~vIr}t zVBRuR#HJU0*0yv2ZL1j*`_J3OJm<2MrxBJ8%6EDr+TLi@mxoIlu7A=IHl(CU zxUGu_X1>0TDFiq1dp+>Fn?ZY|RB&GP#W8`uA7M(h>jf!G(nqAT`VQvjxJTo|3l3sS zum9I>$$ITb@8q|7-m+KdwuPOYoteHiGByqXiw1Sh&f*>XrcBCP8UM~&w0qt0M;lfGW#Rx*E`|D$t7#ZhG#W5-k z|A=;*Qj!^Jx)@24rn1}5g$iFJ`e#d7_u#gkN;ak~@&YkkWk3vf7hV1X(FX56G4Klr z?9YmA)u#0FZPs0Y^DQa8dr-~d)H|s z!mO21WtvR}>70yc)J4+epYHa*4Gs+nfBaZc1 zC!fwOe?cs=DPM-i$x>+Bv8Vm!GQE9pcEYU4n|gxQ4G<8Ea@xJqN=V&08$YFYjV}S3 z*xr|dTK@9W{@m)tB%XT};2JH7WfBT@dqqY@CO*`VXQStNihzht8j`H%t);3Z7qWvr zsmS$uA4dn3w7AL&Q)%!KeS#`D(j(=%sK_2nc}_&>zrQY4vY!PL0;T?(|2JbW=EIDa-v{ zX=_=dH4cbF*aHYuak+X^6LW|KTR;8rj7L277(my>J8%%XjqSQGVWp? zB!KwO`)9!Zsq`7JbNo1BV*p;Gblt>^F4ZMYhorY+A1i&KlrKV&oqebRotRbMXQ7Na z?rUJH_{r?ZGe-hI&MEtU$)A|ddU33*fA@mL(Dvi~wN*niQI+x1s^K)p1pkY-Z{MzC zP{&8;SBuezGx?2;U_GA;0Etct2&PR`TpArzzSKO&cpuA<9#E@4A<{x zzn~J%wKDY9I z^0rG(o(jJ5#wLtmU{1~KVErg-POhir5ithu?hyM{CH3bQ^0|@Jb zeWargb`9TY0uzbqy?9YJB^QZt>6KTwF&P-!gXcB8>0{)QOx-aCf=oK5TO4X*_R(~{ zMjYBhu$J5{(>3$bk~wBvssBQZK;mJcx7e^aD4#siIXOP!_jp)v9wol(%_#m_xi0Ye z!n2@dVJ8lXB)s^70@1E4oh6mxH$CXeHiW^i1geA<}6%dwIZWJtEx##?-7k=Ullx zqXZ;xKa_Mo11lT4rj(=~c{6aKc~atXE&RYGLYkTsrTLgQp_D(w_C2-z*t<8vcj815arpXyw!wD?dnkr0HAi5KR#{u# zCO%Aa-y8RD2=s|q2(JNKNS)lFSA{fyW2=7|XQ9dNNcs*_N~J}dQc?>wI9rPUyDFv8 zz2Sx1oT{?6IV2Wdqo!M|^X7j!4HhZ}w;#`f6-S}|z>V;AW9v`nV9}|w>(rf^-J&zn zvW~9r*=v`JlE7C4BQLlqMP9a^HQ^8n0{9zi! zKjH{7LrDM+8|xNKX4}e`#5=y z7Xn*RLkTcl@Y6R;vaEBRl)0S{`ee&8?@if&0>aJ2Xi+SV{6bK~B{;b_MZki@*~whQ zoj@u4U7w#==l-FKy{Eb@mgX6r+jS|$=`mU1iMkJxpf0O!oWqAf+AeY6)P#yb_zeFs z$vEaB_@YD{4m;ke7^1_e9|Se*3z0rO^@afnD`v~g=x096A491edy9dY4&lYbLb9P*j}Guda*YB&*2#>sM_ zqqY=eR#SilJ13QEX)8iM32d=?t=Y_scgkqAfKKvKPm6IbL!;;M&;{#VX|}Vr=Nyzi z;Y({k<4ySKrNqH~5u<;&k93oLJhDtSE=a_35# z(eh4g^bCV-6PMNU!F*vSPkmcy!CBSCy3a<&fI)oTu z;LV$#^etU)HrY33-iIvxK`x6X?LI3{w&&M~bQoO!#g0wUw*TT!yW6aj*VN$A6;2Fp zdFODDBnbI^C-n*Dcn`Yvh98@rR%G-~blH9l${ll9>(pIG2?Yk0%&s%raY{%&JS{t4 zhK|JMSK9WI!_wuWj<;EUJ{?{te@;bD=yRbse!(?0LK1$&t zu@{!#J~+J8VsVY60BO%U9mp|ty+|dix5nsyXcziXad~n>g^|y7IWZ(!jZDbu28k0S zirAcmuN!WTFvus2ESDX|dKfp^8g%b6I}_4;Jzd42gvQWM|kHYWijVlMvlBW7+A)`3@kY`vlo{oU5;GqmeKByk@h5rubM@cP(Hwz|@dned#xY)VO%P9AH7# z-`Mcqq=*jUV#Mt57BGD%3hEgZm(o^NIz;2_DpOeP8-H2A5WV_x$p!KilUuW6SDxuN z3QhSf0n|A;yTt=0p;TfHyN8hs8K!UHq~FYy1Hn!YH|!?0FXfmZ(A4B4w0*wPv zHJR1p37iqLXdrpuney;;_}*gs33=n4Q?QLoHVrkNJ&}ozA*CtCG1`MWdAs-OCgvTL z!&~Z}AN758q+s)5$CoHfx7Bn-zah?$dsN}w*Q}O1`yr`TFLC6t)LHI{v6|>ou5a%{ z3>$f*o-2;CbgVk7-yrz1R}pVSmH_Ww(-u1tP{qI*4bUc^>7EcP@<tp2iss^>-Lv+98hNOwHJ7w{m}IT|=cqB<~DOD_@bY7e*VRU1~=kh)}`%@V4^) zrinqz!Y{wOzL6BAp+SC1Er3pP=UEpt7m;rv1&5fnPI5Xmu} zh&-PAmv>g6qQ$LShTCZ;-ihK4`9FEs_&1;Kwe6sKZFRbmNImN}b1!Zf=*Uio85KUN zRd*IDjZ}Ktp$wU1atrWbXD_#VJ)H?|m~x`GQ$1g`s}WLLQ!$#vmWO|_e2M;HFEqXlV~PCqVEqq)}%fLczF2W72U2(WA;hBGvbaI|-sf^Ego(>EKqXI(>aMx6n{f+k| zR6dIP#jh^$FA&;)N$7X-r0)&$euT@D%eRIiVBMqPepk_L3FNojq3UH(>V)sB)82;i zCzGu946h6Qm{YS`u|vWrliV1PuUTJ0>h$+K;4ca~jsX8sBl-T7qRCiT)S|oITTp%c z9{Jd8&N`gHpnjG6K$)ax|F8j*X9Sz>Ah6)(oOi{A(-fmKK0Euvgb9%|1V!@uttHvF z4|9w7wg*jR-Jv?-2~pyLN()65HHkW#UN(f^RVEyVTC=|x2pb}l^&?Sw=UdJ4&G{Ky z4=Ucy&j zvVx_S?zs55w{lcLAF6$gt_^z&6SAQoDdOzqy07h9n*g_^&+2@j<+B(O@tl%%(Gy7#JYEv~WAOkabcZja{$^Xt{C;TzDnVg$ z{kQ7Ut@n6Ovun`5>ik^dj(>#a;lW5J7xCERP3GDv$L4Vdm51YGpg;^XK8|g#DO6Bl zf8N1X%!=qbn1Fz@_B<`Pr&h?|Dy7c2B&*gvVXJ3_SOU==9_fv?%Y2!ypl=$ZgU-Jd zhYXc9hne5D_|9sOvJEb%i3OibR;ZFrsD6cxSKJbXZrk2<>Xq(R50?^OE?(dKGAB=n z=`lK!(xlJogXFWBdNsqnrT_E-8DjW!_F`dZn3NmeKHYO28WWLEK`x|<{CWVcUFA-g z$g$~EO$=?2w$x-Okwde69n}yRixsQFGVPBf1=IESqbBIJ4!?+CbRR`QRCluMlkC)5 zc9R%3bPTy6xk>B`zRJ>tu>4zl(?1%JZ!VC+zTszNU|og9hEPjs=Ub%{JMx+*jCH-7 zA;tMP=zc(O2T7>BAXutd6=rENti+7^xWMo!!zM(X$Y^fhb)}=sW{o#uQ9u^s{!d3O z7D7n{r$eTt{V(3Ze;({$b2tX{`>e9!EEOC>X&OTS^jj(oI2fmdpU)J){%SrX>>mwO zU|~=}S5047jt-w41KKI)fNtSQO2UG`m;}8aFLoOsIbsGcqG9P6h8lfwhLJyMG=d?+ z6gYK1zb$lA@tGd~+;X^hV2Mpp^07_2?^#v(@%0$6dvb`L9X%UImEQoWd?-|=ffx|U zS*>KGJw9NXdOeV#|H%k!_~XGe$CP-59sVAZ0+;$Ioucw=5N&;!4Ch?e&e>%^($?J| zH_6fa&1GGQ&@OHAuFBckX}>${;en3r<|6r2I~?GsG%Gr^fW-c=v`km+tsNoxn}rTT zf3uLx*GC$mQ9wS;{^dN|ZhV^v4$A{Qd_~k_K6mogTTD1SyhOsg;Mu{}+t+aP=sg7; ztu#$eoXJu_Wkaa{_0SL~GU!AQDnk<(4d%`d#E193sc(>W9DcjHF;(Y@T2mw9aG}l0 z{(Be$b!w&p6SV4pO5y1RuhZfzJoOoW!)>IWplsg~bBy+xuk-Lom+fsRdxRI1u~3P$ zmi)zY294WQrdYB~2*!thrVoEC^~TxP5aO&xiKG_5IRa7Ce{CxC6cIr|nOCesdE#_1 z0g76npK;pGEq2{BF>CuR?-;6EX)!jlvV;AKxv*YZxYR;RG?M2ZS8);GD&`-DHWy0M zGVe722m{Q+LqJ4C)abg&^YHqrSuv`67*+dSO6bdR=b&h?(^le+{FqxV#*i7<@V&ic?5auC6WB=lb$KHArrChz1;{B!qVD$2hVmC ztNDtTd1qbz^eoz?En4fVNDfxMH<<&Nu1yQ;eK`|7Mk#O;DYe_B{x_F;X5SMslzh&M z-9i+GL=TEfZ!R0|MQZduFXH|AKyxUb734Yz?Vj-aaR;4>OHy9?;I|Ur8boaS4*{VF z5D);t^+_RIAi1xvuhIRoM2PWtrEMv%U6Ky}<}*<==I6T3N<8{Q8)V;hFZYce1ROTU zT%+)PaYyNJaG9DAe8m5tME;c$Hp7l?0F$4Wpa1gn(a$F85?=`kiORY?;Gpwq8Gosu2F#3`9oQNO zqi*(B4fv;X;a?pI{{e3GVx5Gct*)oJYxy(goVh;+K-)23QF!Gc{v<b%=y7mxV&mhfhh-NVZ1s3~c|mzo zy}e=%U$tv&jN{{4g89cED5pz8ftH6(V0!1V46IDIBERx|Wph&`69NMM~4H-4-ZF4;g=7B%SA-S+?R&2#N8?zG?6cx9AI-otYF*&1%~Mjc!_gzP%|-i9}3ig?S^@8aA0x#gWK5^ zM(7q#W53Onb*bKRRC03rsWp7OR@3za6=+F7|*=j6pvmTTt`vai~x1FKmLu9coqvi+xfJ77V{cGezDG(uyZ}(C^ z!<||XHN88v@u~89xH3~ytM}uZr`13ApFd2fSL?s#f~~qyL&28(*xU;hupD*_WFY&t-K8$Z2k_|yT~;F!M1g>X=r;Wen9{B zfDP4!(W=x-{E`a3kJX=y)- zcUv1)iwS3gI)RO(YPNYvsp7{Y}*2J}VDv>EQ+PYyc)JCEU^#YB$aCDsU}V zzkO|FXb8_D+tUjXxjsFGJ%`H3Z@~go;Pe^LY308?T{#4pfC8g5e5m6=o+S0c}&VAn-YRyZ1XFA&eMgsXa#-?G~IJ2?eeS(qtCBkE(;c zp*Vrb&L84J@@nDR?%YCo&w(bJ1>lQd&H3BWZPwEaLyU%q27KSJ1s%Q==7KGVXDAzOu28WJK{$o#>ue!FJHi z1jH4RxFAI_fSEL*Zkfs$?7ui%u5vcgTOjHFEw!s6o*e}Jps7j8$cTJ>y!uUp0>AZq zN|wdG^lJ|OSuGTAW%Uy-eOz_ZY$9$QGyI*_MK97hz2T0SWCb2af;_j{(D-|Z+B`Zn zgCmTy90{EFdkLUdj0`s;5v%E-a_bCisA0SovoBP3$pafU8zP_#yZh$|ArPG!U>e;L z>e!sPw%FFMcmCD6v=60ItRq9wt9{;3M%nt~sVPf@R#s6Qj!m=cvADYGU>iSYEf9yWvK5np6|ZGIB8S zDdywX0eXDKQLBTpWXrdgKu)r6+K^t$Ft6pk5{nx}c-zWYWvGXai%ussHX2;5jOc;n z5}-*y^#+V0ea&d_kqb9R7h=b;ZR(sUgB3f1E(?L3b>dQO+pauDTXToqVfOHGYq1IR zU4~LQELQEpNI=ZSGeZ55F#MLSwBn7~iSU^;eE<)-BZAMhh&K}(f$wYQmrkmhsq3FL zMgx+=$>!h0R~JSLDV++yOL_($E9l@cp0CCS8En4wDu3nZEbB)DFib- zY+U0;Mz#A=NbfotJ@ovuUr|@Bw-LG4Bk8e^lEEl1P{G&t({4nDcrnbYu6_2S-<U?h6`@vU0HJvqf3P_mT4*yvBL?&+sbH zE3(kG6>c>bqBOws#qbTa%KqL?YCX8_{h7oTJBI;<$P8p*-$vUBvF3m8S4yMIYTl~G zE-@W8+hQl(teT%LkzuAzzW>-wZ^!rm&!qNW?MmBT((((z->V7i21oj13MLJl8u%RC z09QM-?ZajM?~M&AR8LV4u@A$F z0UktP#}Tdo&p(*s;bfR>`6Ld1SjfN@>I*F!M7_*_)6?qFBvK%GG`{J9od1s?Oc!+v z)ww=-cRQEJ0zL`vmy!O9&xu{kGx!EL&7w~11Uc!=l%JMhT&F%7wR}M(Y~ti9@0g!1 zRG=75<&eCHk5U#|lZMbUFNgh?FqgW2)t0~=YrRiZ={`>s;B5~B;NGr9r_a4HyV^VQ zhLR%ff1d7tNSsin9z3vnESLPN>uOfOa)tqyfB*#p^TDi}x6M~&J4^gm=)U4G8P@tW zTn16-Ygx%(NAQ(X?ii_IZAK-7@xS}+;lH%Lj7)q@Rfrzwg#)jW=|%`UpCx%wn`3_C z91~;{K2MvRuYpM#9}qMV`KiXC2YnSBQ(9fg_v*zfl%L>1&40XDxb#U9Iuwwl(L^EYDB9`=#JBWcP zOE5*%UtP3weWAdW0p<(Vx;m4_9W59Up6G?H!3X2jq?Tj`z zmd+D+KK7FS{n{T>#LlA9UXW{jB&i2huWLKezr6q&r%ax$tyl#yqAF>@3wjXhH>HH# z{`~@XRD*6ba0ko=y2agDJ;7BKC*U$fH-nnO$TFyL)JnKzz0u2}j#4ZPyzct#PI43hBzLPhGN~^T74aAkJ z0_QJq&2(RiIt`he1I<0wlXkHQO&gQc57$R+cGqX!jrNKbgHy-6l&YnJ+TNdi`Q|PI_x+?hI>sXxb8tf@d4`o-m1)2)<6#+(~|5O*f8;SXj{f+2+xpM3Nsf z>f-~mp88gT$%%Hm&Puc9BiYp`@(k^VT^Ft^(vZI9w-TN*6L;_PFQ;i%H5BcV2sP-7kK>jWD+5c@%Hc#KBg3 z*!9!C6K@Md5vKhZ*_u|<5qgJLT|YlC{O&N~=}v+K_GJsd;bMzxa=)}(PYDy0j@zv+ zfZ1uA;r<2SW;VTqGJBxN5bnPHdec!Z3UmRUhAUHuiESwnB)v2v!)t4SBSw2~+w6O? zzZ0Ts^3tjZtBH~#4NE7M@i_Vyk1;R4H`=?)Bj3^e2}l&oRlWSXmSCG zTZJ##Eu)RzvlKKvt1blX^Mh5!n|f7ge+q5-xuV1bQ-dKPgNS9rru0<4WKjTJ8_;CZ&d!h(qD%S^u2 z{9?VCeO2rz0plsCdURhrU}FhtV)7~iA`vH)6N*oH~wlHPV``=*X41{9JKA&tha2jM?h=qkecB{5}zct z={8~ptOHP6DP%%d#Ah}XswlBe{tsVo!4=ombPHp_r5ks54GzH_f=h6B4Nh=^H*SGO zLm&`>yF&=>F2NlVG`P#RIp=xb@!UJccYgrQ-fP!dYu2n;vwZK3NOODh58jxzV8btk zqYNY^^r=R|aaN~h5jL=6KHpu@N(TOoKM_0g`TJRf+T~!b+}fZkL~&(hg(M)6&9F&r z9us;-t<_oYFpppVD(hQ}!AH&Uqs~naj6P*#=_aE>5Mymi)rL=R#H`J40vpPi7Tm0B zvL4KOyj2|PGK1#s?@cP^K_dOz4%}>+5p=VG zWY`hdz5quwXc_uBz-Ug{H$a^}Fs8Mm(CmqVnB3`oJ}T6idOhG>%)ritY7VI6a?ctg z-f2kcBI#bOrZx?J6jawF_JFAEqdm(|1Fjn++*lLE%G>E>4r5~sGv84QL%zn~r-V*W zvJ0an5wL6!?S|o5d|bx4g~T#T*mF`+%;TKni(z#H&rWV`H-B>c<0RP4Z-8dH+K;BdqDAKG?vKOC3bzBwGEsbZhe`P(-u zQgRCPU6}#xKlQ&KvNRVHEq|Pk2_d7PBpD`nQk01o{0)j4=x^w;s5*{+l{R(}PBGuy z|Nq}28N-+?jSMRSMvfDT6$?6x+Fk~}RCmYoqx0bH1wbcg=yUzKyvrX^?Q1AsGo6M~ z>ovBZ7jcM!sJAW@jlQ_>hKh7tS6!4M?(Cl+xBUnX>J;2U_xc9Z7*`2up$Mi-W9E~-+Q0rwBg0QggE@AtO1-d*d2Yz; z@}NcjiAzwp@7}b#wZf(BM}~sW9(r1kJEAKS9b?kq#vvCm1>0%3vx)E|RbzMZDIP>n zAI4zUHAgLM_5h1&-ye2LOPu52$4QP5MyU;>+7D+D$LE|#r20{wzA{xEQ>!sVf%l9s z%kWsx$rBbDWMT~}?ss?58JeYV`AfebtlTI3mV(DGjG5O)?UOj`=eat+f{ z=@vftW3=k=8sp+_#ozLI1@kmFAVPuD{--Z1_Vo|+ei{SQM>E9Nf%u>G*LgzH?ywfzY_Q+iTrH4Y-eKL(`ilrsbYB@iq;{kY5&L#S(8rUz`F3!ydq zfeD&R2-t-1YwHNYnCJe&$_}1o&<^GSvD;vq=2hs1*gT;^QN?B(vCByinL;eG$t~>v zp}hGXz0ADqB0NMv-VBI)h#!vKaBkRrFmNn>NZ7u8RThB}-jNS?TEvxD#@ES05ouoJ z$(#lVkiKhvP-CwB$@)xnavelO&d`CY%w8JJ9g%9zW6p=s8F9M=Dn}^8<#RdoAy5Ef zIQ3G-a>hWnWGC>P*iCSu7jcWtS+T)pmFNnfrmoGI;|=+~SDy*PVOl|!*npIT+~o5( z+nH>_g(nY!evV<_#iU$<0Z9)&#vS}-yHNQGJ97eP0txo79rV%|0nnLOs3sYnFCWbj z03SdjO4BSgSRc8zr#SG<7=-T_MeBJ#eE*g z1%9}r2rAKg5x-r1{(q==_TB4-?q3u?XUb*dqnKNGTQ^AuYW7MS!mB9pA{5kt%Cvol z?7<7$&5XA_C=)eopWELFH`loZy*kZp>2458Y(G#G2vmo`A)p|A_U0*555BoP;M|hq zCADUkTuko6ntici8uT=$vN8lyx-Fn*cX@@AZ*%d}qvb7?vL`r+dWJt{2SY6X253?v z=%WOysIph~{B$*gtC$7xz+Sh`SKVl~4TiXcm7kciV$6T!E$N&;^D!w4JfH;}tcFyr zzWmC+O%Gs3&0~tSW$!+dHRfdlxIoM?cf#Q5v=ZdftvhBnLHlEK+V%x3@i+Ll(q>;< zRA&78uv|U|;Sbj2&0kNKo>T%2bI8`E4c+M4>s9^fJY8rGH!!<$SIo(NNUxcZvn_;>4b4Ap2YGH?yahItnjB zvW2&r^mt$Y<$d?f_&ybi(1>qqpf~dri?Z0FQ+&W76~pq!-ND*9tE`rI51+6soSoRZ zu^brW&BKMrwq4_OzX+!&dKK>6UOP+g;!!Oz6$vDaJ~wxP2~w8>g`91>V|{MWmQ-HZ zN?5NGH61_pgXH1Xy>u}K)JbNXn~{K5!~NG0T-FRBfvmw)gN3QBSozlab8>YF82(87 zq8}FK26h%|ZBEC7o;1&9s*XdkKzl;(+(aiDnmk4rKueFP7+XOp!Z%|8s7|y|Yut>`(pc z*!l`#j7tJhp6=(v<{`k4g#bU0C>rByD{O~x*mHLKjj>TXn7|7*s1OB_ z_ut3&9m0Oc@R%HSMH3cxwPhoJ-HKBwKKpoTGvB8l5E8{I@**wRy2h{+zR!QAKn zsEWc?RpEU1lZRQve!6bx8CpDZ9KXBy5X6`*WF-enoHD%6=38}ibm{UyjYYT{TBmGW zB?CyA?zQIAoCzn+3v&LSa;ZWq;W>;yw}-0a^)?sv3n_dg<+niqSx#^!dOpJ4wWgq; z&_z*gH;_o>ecDTK`gH#nO$U5=G@M`1Q~19Y1C@Zqz`Os;Vj#XR63xS^U=0QK5riBs z^6}SG6U>|xsWi*L_;^3yE)fHCXT*$Y(#+@Eo{|Z9A#*T66oAeGf(klwg0=ks8H86C zkl;+qMIyL6#EU=oGI|8$!ji4r{~T)6cp?kbq?;vLv3g>Y0B8F&-=0MOc#!bg?@?7pUC(z+VFA+cNCeY2l*! z2^m(^ZRGyJNZQB4foI5mpfIU2*0U9x#lw5$cVu@#|#UriZ{YYp-02RqwZww z(37Q_$tQ^Q`1j5RuZ^9}J@0?~7xdbo-)Hdnr0A*Ll*D*$v0LfU%!J0MYR6i)^R*7B z3Y6lyvvdF2jxTt^i28U6FD|tjlo;$mGzZrOyVB%^Ke9y)z9un^0dsV)E=tbJt^Dh< zp#L6rGEc_YjcFI?Z1ghH(9?v<#Neaw|4?jR<`aA7YH+^C;tQlYW6q~1F^*b}`H-aN zZmsYhj$a3-+_^RSICu_UX;^MTsH5wt-3X_w;F6m$NUc|oE!xFRt`+hf@3;8$rDw{#VY$ zYAEA@OmXxU4_T)<+X#gRdwA_4I0(>=1aOY8A)Ly+rzB}#=d|MDYkS;g&QE5ssq*h8 z>ZvM)m{J>_b3Z4D>K;#q{nj`s=`)+mMCjSk{sQg7JePx7NGXxO#lvy&l$)J>duq^V z_S8T!FgL(?@0H;c>6uk$WHU>59w zUqXC(N~w066EFWfjB)=IAN4t14ng<$X72qofn>Sv>ls8Jm4sb81dFTdpJCF#+`AJ6hF7)>i>meO>$V>)_u7ue$JJeRDB!q5Jz> zmfAIX@))1=7^(~9!ky%q z(3=@)(c-T5dE&ORM&`H<9ux5Ia4HxQx90UHexJdgDBu`!&)o_f#cKo6pMg9>ZD-7v zSbkNVYiovprK&GeHcpbm$XgBC5Kc{WD7ibxs}7JVKT_$|TNA?389pV|U!s~%9aTN0 zfRQafbO#!Q?^k2$^5i*beR+5KM&Gc6?vpZhJXv}Z+OLi2aYa+Hd8Dn!TpSFDpvkAU zUaPq{A>`;g+<@}?_0FUZVRSt0SCfr-MbM9(m})ji#gztp7|xYkB4dSdh5%by=Z9nH zm#={)XfTC`k5B&qWYXV0L>m@sZO#;H4hZ|enS`+?jhQIZO`R#`P04?#Tb{(|l)^9^ zwU9O}VL1oo27)7p?7yT5QcgHi=l8e%tUlwS_A&~SY~q!V*nglw7SWD`On_KZzn-pp z6{7J~q_27pMvkSVK4IinV0LAhsZvRUpm7N$C&K33^QnpU14l+6KBqTnn5lW3`^BBv zoO}bL95TUu_^LOm65m;|mblOoi_$vXXDl6&&pyJ*KvrCliQ;M2-x)-Y_z?@d@u7B` z!$sgN_j~^=VlTX59akoaA&Ji_Sx^RZy7xOt-wn&&LFmRuSyt%_H`g`8#v}ES-PNIN zK_N2RQs{|0SDAq*Rt({GI79V`IBdu~>{WvesNtS@o1I+^iYIa0fqWXsWoeZoxm*ax zI6J4t*hk4_OAXh0s{A%H0+IFk4N*#Nb`%k}^&clJRu|X%E2oVCd9UE$;>Tu%&8dl% z%|2->MNGxJeAa=UG`6LaOB?KpAfEX#3hMKFw`_K&LzKg8Bx=hahEqBjcbjZwcR8s0 z3Q}NB6HFgvUauhi2&HD6O;NXClNiJW;}2io_>n{r+|xMLi{Q>O_mnk-Cl{_N>qs}G z)PC(P{8Xdx*F=b3j-XQNkGq~O!6P#+>ei&9dk3RW%rFwx0jJw-q?*_a<$=k;`T=K| zh5sVn+Eh&M&Nc!6)?q5OV}f3oi6~Q`5wwD&ev=Cj1${WK%PE=VC$Wx2eSY{Y*2#A> zu;W&>R9=Ub#brZ1x41~Wl$-s2B(|Ufx}DqA@bFFZZCMT&e;ZAV30!y8W2ITgGwQ`d z{U}1oF)aJAqrpheCjQ{fyP0yek$50XtLiSfI7!2Cp)*iwDsW)~tK*4Gb1-x-gc zxKo71&aBK=5XJEq`E*ya;*gA`b~^WAJG#81**Xkt%dtr?Vf!2bY9=jVwbQFH6767FViqWvm2Al^aqDQh4TCX?4Pu5Q4_LzwAfc{jnO4a90QqDHu2n( zfjk?HKB z>otC>srsJ zoU1r!2-Nd5PbW!YMvw|x_5T!Zo;}P`E9tlEo#-FOGYVjGiL`b10HumwE`>;1%;?8(evwy-LdHUz%2dLxb#OG*Srd>W#L?D!^ErtO2kDlbha4@?7K;hKWY*p zZ^j+Org0qrdN4KkT}82rgqebt)um^wU~8a0Re~w&V@~bI`2x+Kb%l^wGSxK^F27q$Z--t@WNV997m~?$H=}yNko`yRE1r|mZv%`=^K~aK;E;M9ebl5GrGZzj z2JDbwo@>)XO!Iy}*k&8es@)p4RrD+*nTVTf7<v9XCz ztp;M!U?l>}0PU9hE}-6dTEHJg2!Iw|OL*U4$vu<4>f8 z6kWA5Pb2(Tfkpj(hlbTSF0tdDda+1_amkA@vC2m`=G6r8r$1@sYXLp&fn>#8NYWKV z=z6}Kn^*RrvtwOp)$ib*ogaZ-$Oc;oYniBd%dfER&18FASUtY?j+I+AtqYS1@nOCS zJDctNP)w5l`zrkGzyKmLKVj=o2f6<4^!j%*mA82r8E*gCX&qOG2(2GW-1H|6EpZulhuu0fzr+P--M%>ZrFx@tZ@VOA zYD%eHrfc?Ab2=;1lhsj<-63dKSdJZkGrZ#)GX25sQ>I0Ld;4=AWd3E3kii{-%rmreOyKoPsr(S zP{(OR&k?!a)vNLId@LvSyyBHI95W1_S0B-lnXlRcVKxe)_rr2<7=N_EU`QwjGCs#Wl<~-_g5~mF0aBvamr1wYGpDXHtiT2Ynu_Zp{v~ zaGpg@io>8&b56@7QAqCir&2_{HR$H+LojCxcB%gRKW08UtM<_?_3?yt3lo|~!Ivzl z1DQg^gX6{E_B;HyyMENC1lQn4bIzF!iz=s#F{-mSRt~X!t8ynoq7aln@ZU?T%&bJY zY<#H&OC&&0J54#WYm&pzuL^ZT#JvS@81hReG^=BFvFXen{G`0893Lte8sa!oPRPaI zsf8v-a(TxcBN5HW`_dp8Ok5Zn`MbX-B7inVm>v|dclj<~9XNh|?J!v0(T9QK)zl!o z8KZ2%YTQN`igX|Z)7Qox4Q;Y4)P1;O&u-O^b^V&1lmQC=5ui+{Hd>0gbBuuSlO4m#+89W-Z?fb&Zga|c0I!qQ0|3@ zhT~&61VwPeW1Has6wTDY@oL5?LWE?m0@c!Gix4@NnJDbNW>m4Td)6 zWb*sfo7niZJ3tHEatm!X-Nv#7Z#E(+^sOkkEFo1)oin|&M*$<%9o6;xyP`fac2dL>nZ$D(?p|T_sEd|_?^G@$d0OlagcfEF!T2NA;Y$ss@dWbdOWBTt!dI* zKxdV5rZ{R@Z0B0MW1I2=Fa>BvFl{%9QOj@yJsb^#??=@O7JO;m{DeOna_q@v4{7tc z_Tf#wI_ydl3OMN*DU{@4=RP87OVUC5&8cefnwAjj2lw0G$!<3362{=V^wy z2`I9iqYark3Mn5*PcC8ykv%5SyXC7&kpBK^Q z*&dHw$=`HyjiA^{V3UW_ljOvU>-k`4Kl7sasThNY&PFu1s_7Olwj%YlA^Z$+!Lzfy zJ9aCm=)?@t~C_2kLzIz&HGwy2I&Kk^E56aFBtxkvFy(66(6x z2d24J;?M71*BP`)`yjg7I8&Y*lUaJHAYY(~*R82(p*esHW!SM662!lJ!zJ1w9>@^} zub4MB{kawoU1nhbXX(Kd_Td{JvnLW5OYKfj(jxhZ8|Oq`78kkX&*A5tr%`ICN6mb- z11gmK#}zsQiJns7;_#cvrzy z9;7eFl4It|ve_bZEW3$w6$ zh25A&<1C$GI#(X*o_YeCIDBHv2UBvP(et-Fbc;jZ@sAx9ySmYWir$U#vwd%2c{!Wt z{UJ9Gk8Q%Vt>Zh#+Hp-)5i1oOhtyx#@VA}r{8fiXxpUT$N~e8F&+6%1V;GwK%@!Zy zlD;-H&BmjjO0S#0M+v-9kD>@<6(2fvTyFm*PMt+7lSIfi7oys8{b*@x7*S$Kyq^l;{5|}L*W+|-fEhp`gLO9@d9ELBSiK zDly%61N5xC_G|FTqOX%>qhilEA}vJiSn~qOjjgRCVe0K`Afr=ofu3u9`O?O(HuTvQ zU8mHj6b#)wbHNt0>_XU1QozNvVAX4-^98Ari-*#}0&{MSI9l4QTe)Abb8~n`5;X{BSsnO)8v~ps5$$q^=SCu<2Gitc3UmDcB4XsI>@~ zKKwCD7ny`Vr%wneZe8S)XOV&g!Yuc7tndXed0O+=h{pYrrzOn(8FBHAHazRB;TG_@ zY5iN3%$IrUN~yPZhU{;A4Kf2*>rc}fN6KfH32CzBLWlT`JcyPZ*VLx+hW6mWp`k9o zlc}@k+ws=%as2wasX~9aUWoFtKizQEhyq?DT*F7 zLM)A1ejr376ERG#Y;R@L?RPwzZZprgfcd8o&>vW2|Igb|f}I_XAB@ahT{*q}uEw>r zwD9p-A8_P)Z=xU|AVBnE6sW@~?Bs!_4B*K#vQpq99durIYXA1)5`9O_5+)9nSnqn& z*Sfng>l?{vH!uvm+Y_sDS;Y{*D*ekfmKOqoOB4T6P{(maN*bP+*elE5uJ!KS2B27Z z)f%a{#_h5$P8BWawmsk#vj{A4c{5M0$Tt5u=ZyYDAg+I%9ZnbGAd~MPmVV7lFNjg2 zG)c>oBFW(wA9O?`KmnSIuPPKshzXBn7GkpG0MnYj_FW+CqaLzhlQ2wby=v$5bpQ7z zOO7d99-s^dif5S;aWpbW1k=bO%i%XSHT_}BDtv=4C9dW%&Kj-jFaBpV(87uFsT&I{ zY)cuj0mkK#8H+5lESv_LYHk#22e{Og5Le2`)VIjaYgmXw37{h^6al!ARdl^BSf#diQDRfM*x+YocJUl`?|ih^3@1p z9!|+?H+f}Ct5Z``E^I<1eA*w+DxNZ61DzQZ!#-MpT`0H^u*gM1pp_gzugzlH%WF4+ zpj`x34@k(EC0$i{ylNA;%~lKYb3*8_e0avbHlX;=RoxC9cl9SS0PM9#yWdI>3&DuR zA{Pd+ak0%-CpOiwh7UMDobcASXK28kWifr<8$EyD5&;%4w7@#<=V8BnPlEqq-xZJFf{Ai+>H0(Ru--3W4gq8uJOY`_%F z%*yIjbK5DGnxfe5jI#X#>#SX}OWHn)-QJ+{)QLR@Z#}=LE;d8q)_i$S;l)1DxJ2Bz zfULQO+7?b|aubiRz)RDrnaJ+WFchPr-?Ff}wzk_MK_mj82qfuKqFBBV6?@MpA09*j zqp-L>$3Iw;(r_|CfFW7f&I4KOFrjinG<-EJNBG!dr`PY^3^KkZDCMinECN_nU{M0uo*QpAQD>LYlv8k!zf zF@kZ@4w(nfe~)jiw)@GV{as&&QB_r?%4FI}r^SZK=J7JY*7K*BPG=P}pl@G*#}csa zSk?Vf;yGS^W=iiX0}`(&`)jZCrkS*~+oQR11E2?)`TcSeRS9-OLjxhN{U=JE1q|`S zA%$uzjBQ{7nHU-H5d|~=E2Q`yz#XF!)uUoS@kLTv zQ;8>K$D%8_d~zmQx#7O8y@m5%ohEN>S>Xc_VhH%ff_ zIvD=0-d6;}>!EEDPhhZ;ubfSN1(^PHr2HoSx1L7JK{-t@#L5NRJ@U5tOKv+uw&0%>;oBqr&#~%2)w6)fua__=pPN> zBhmc(k)(jIv0jldY+&62;!I6Tixznl=nb9J{H;#{JVoH4@F?J<=q|P^PoTO2yI~wh z+;P(l?Yd}eHwtZ(#8L=;Ad3mQCt`LWH?3Mm^ji(W{Bax~LPvb4 z1T!O!4_qo$K(uxy>FuHX8?S($b3EW@7m{>5RSih8b>VQkn$iPmlL#0q8=zkjHu4mS$B&m17~Dus>`_ zuTp;F82`oZ(l7|3fBmQv!07nKm)@InHP8$Ddwa%keD2wY{ww;1tAC+G{9={|DU+K* z5)fXKDWNap-xvw^jwcb1E(BxjnN#0>N=;Qj>|b3qhS=Av0UgLcdx~a?=olE<+c5aw zGM|WXAfiogtQ?tXZo3<=vE$xrbU9Qt+LggB?W}=SKm4}zBLqV1HKY$lRNyL%^W$vr ze{G&CWY^*tge8O?K6uXR!9d{LPDH?8S{eN|y1?@WC-aaYWiWPe!tG4ji>T}AQ&`ei zsO#36Gx6xJcQ|3sf(rB7fSCb^lLb!R(9I1uN>NmNits0r95(d9#nCDXc?e5)p9k=B z%-#$8fwVfpUHR%G5o-Y!eh#I2YU_6~TKXZ5VSUF~P-l1xCRI@i< zcl`Tq?eYtH>k|iF7UnjM<~uBs{=D=z+@K(TSJVfj2Aww6u<={csQpfef;Y}zAH|aB zf*usVG4o54lyKg!t;zRIf9hZC}7O!>61Or&|oW zr0ijn7aN*wtMEumL0Oy&*!xBS1Nf4g>Og5Tc4x3@Z8*vue-MbrAJE@7A^Ct#bfgR73=#zPlZ^kiJcRU@|2-vyutLAb~+C|SVoA97BuoDo1pl{329tkNv!PGw8 z^9$5$7fH<=#0MZItXX~4I*xJHu%`6f^YYKXE4F@Yx2EQvB>T&&98;;g7ujO*JF%oJ zvTGPC$e#gsgC^_!9Mf2r9|fs&*Dcqw+I4v3HDTM`K3rKA52z^(_4&l2iIO6`UUkmm zSEspm)xe+RhV#=}n#K)VYtiJVCWK&7RA5JE=4h#8p1<8^7?nr>3{Uf}Q|J_3|Ggai z>v1J~qHx`r6+F3-M1H_aIyse7@?}imvhXe8LEjaDu+P}8B;xCHAIP)F9n@Dhanjp8 zu;RN={vPXMsWe>%hfk3!sb(3&I{~&ule@G$Bx?SPTgu%^0!#47dOC+*FiQ z>xnO1QUfA?62w-7vH8G%gI*@Nn}GNI6Na2&*MV-)du*t3*v6}_sr^t0% zHRX%ANZ?JsSe2zSZy$RQp5S>cF%8tEYcavN`zmDUS(4QL7qB!f)H?E zPg3xOV^AGvI-hkHd;UC8b(D!Kcx@#6pj$Akp_~-EOmbDDa=5aOlb#@0Z(^# zE&&_c)D2+VfDNT(FRYbS#k2=Tg#xJ)maJK$cR+xMcKb60X@~dpP3G_}*?L^~ccH6S z!hs*ag-RENfML+%C=PT?^RsN%Szft=Ko16$z$9Tatt*qMQ~*kctaw)jR$31*ZZa9j z#+Y(=X#raZ*-6BhuK8U?YP;6n)ElQ6uby3i`Y28v@ae}2H8{l2Jv#uhRw*F0k2aJw z-LHr{d2Vv$zcW6nmc@!b>Ajvs*5g79ttau72bO1hnO5HL4E9q`p$BlTBsYB;BL;BN zYZ_NObwZgK#Xq0j_t@of&Q!Jpq49wE#fA?n{#dg=WJatbCikcuep@A-*A-PXa6Hea z(fgcg|IH?sVNUo7Zybs5-7u0x$+fuFGV9M*sidV(Pb9SHg7Qhj_*!3rvrSqlf$&k> z1Uypz@Bi8xqo|FZL*n~WdVPfHW-EsK^*d0Svg)Z`*s~Yb58!B6cb!gZnI+5eaQ-ui z2X&mjUMZcw=#=pHFCpYF3GO_8uiJLR)YfQTS1>@A<35wQ0Ls6}Q^+&( z->~SjcJ-ldMK=q28xm>$`YdH_`z9iu7w_peE$y*LKE-o{{n*l11f0QZ#(Dr<+GwVoVrJ+P#?x)I&ZcV-35OXS}2hLK;`8IZ9Cj7sx+@E z$BR-_nMi5chNq2#1rRk5mHpajkS`A(3sq8H0t@hiu`as3OdLS0QYkL=c(2I z{w5gP52lVZ>@1}e>jXhJ*aYWq!y6s-TVWia^(KCyI^u-52Qu0chC8i0452AHAui=}W}p#ZS#J%z4U zQSxR?AsTfO2shTWdrpBCa49mc6O5XuzVP{NGLC%a(TA9e9`lltcax2XPq&q^zV)GM zB$OL7>5toVqxBC`dHqLpguL<Y9wzlD7G8tP0&Sy@%U_^SuOQ)FfbeN|2ae5bv+ zuYrQEI()2&5i$QnMq*LqS5<*ty?Uj_oT^r=MIWUsCnrahU;GG&G{Br=>(B&cDS5vQKtv~` zgeU>&nS{&L-gJ>7kRpo|6#RAUP+%&Zsng;whU}@TZUF%FKPQQZ;P+G4;3P!1z}F26 z6Wx;@jgaG&jv$kCNgFYG0S9|~T8Rn3{8c!f#NC$yROBaC7Q*jND01EvoD zSN?#TTF)5UZfv-pZ=k2gR5oiVnS!FiR}Q2y2U-i59vmDTR3&ycHVk~F+aAC-j2JOR z#C~ypQhD1y`LscVQz(DttK7h3JM&$=%X#99gg@z=WiM_AAgM*?wi)9oCY@PT3Mp5n*L<)Z%Nlgv z{c^2otauyOLx*C+jt+nY47_+CoqUgz?{~r3k2HKdqEN5T22pCz1|FJ8^AF(19x`xo za`JP%GjtSDlbInVCZ-zT?}V?H-T$n0bZlRLu<0NwWt|-*l-zt`Pfgh@BUYKkd61pn zDek@fe+-nQYN;FaxmtLsELA6QVh_`$#(HYcJbYEfsnO1~kpv!wjJh><8K~4s0wGJp7?|2?a@&jbqjIt8 z+fyN!du;F_uc&a96v;p%Y*@FWh6p6*DgUHq7knx;rHl)onze1`=H`fBO)oC$r*qjz zrWnZ#&fV{eY6v!4^kY($43Rf9GYShY+Y0K_Puv}a#*v)1g^EO69k4Ko(a|HcpurW| z^ZxkWlJLFWAuEQpzCEg(MTQ-y=cch7eX9imq`j^YW7{yhp#SBqYuYnXlx%A-B$RA- zcXvZ_s_hQV7(%KTw*Wd^UpY&0XFHN2aDM+C8a^v1UJ?8Lb%)XDSl`5QsrSg7tRvrB zIb;t-1a?uiuglXU616r4JU@Yp3!r@vsXfJCUl+FfQ1TPBrri!YKTOc7@R=9K*;-p! zp=kcTyu3UL8OetpR$T!WU1&mM^+K}?okxA2{jQIJfoOT}Y5>Y{9oq3wSY0+6WD~fQ zb;gE&^|jb#@{4-c`xx=4JE|Y0&Oi5g9pnx5r($@3`O#2mRKWckZxa~Y{=yycM5X{q zQSe|GeU_w6S8aPF%G(C^lp_HOpc{7*^>x{pE#KtP2q=X)& zsQ4xs5kd4%vOHk3|B_8%Gu)aDw&q$!N}IHJpy*T@^S*H!^U74s7Eo{6GQ6H7mnx|I z=4g?Sz7z@|w=I-^IrT#rvD0IoB^EA#5FvdFkdt)46#~qiHzkfg98tm_1x9(eoyR*% zrOm@0rO+#5^TAdd{XVqwK~H)wT0IGnTHkKt-8@YYecV;p*~eR-*6D;I{e6clpO}K5w7Z*Y5DGJdiYdOQy9T!2v~) zpQ>a#V-E!|FxW5((h^#ecJ`$bp=4r_02lF3HcbNy4x) z8tE9~n?Bmue9^5!NQ!?rp;HWli5kXShl#=!rA+x}k#PTAqy?f!+8DK(Q8A!jijOdd zM_YSmmYv6?!iE_TBpD%f9jI zV!nl;+k89lo`#*5xxhMG#ypTnt129NFCdK+9}IO7E<$W>W&qlfVSMa~{N3B1+DAjI$bU-Bf*qXT45{N2)|d5bA;IC+ZVB zY^b^5RMu2d(;KX-LWn)zlwHtLtBp%(zAa%t>F zCHy7;RemPi<9|!j255Z4yxdiHtfUJ*QG4`io(w5TSneRuj-QKf6=ne9$unBZT6x2_ z^okq&k;Qu_(z&0<>l|JM7{p~KP3Aa0HH8Y~e3d#F3umdTl z#etFR6?}>3FQlfuvp=ZtYK~Zro=?v*#Rco7U_F!eNq`(X?Ax6s@t-FX|%8bD^5x1Sg4LRYCa2tsm*H{_U6vDP>gnu zLj(Y4g6w@$0NpU5M}!pI*68!)A}v@r-wuffW53Fs zUY@DxUhmQ5QK!ncdXOzl+3aVnPGXH!eAX?fnmr#&`)z3d%TPu9u#EFWl1^jliUyog z%{C7oUvjQnUxXaoSqti%Gu-{$bBFW6cC-*d^(vy^5(7i`>K)g&k<4&FI4z!M+qx8U zX>llZ^wO_NVB$aNPm-qPFK?Lk>CY=&=0x+UtR=f>AGu*3o_PfTgZcve`~RM#eXeES zzyBOcWdY;i(IG2Zs1ByG+?WpI)0R(k@M#7G(!(TdN{4bDL_8l~%}dfE+IA{Mj66bT-iJx6E|aO3$Yt5-21%eBS`S~0hRM$u5)mD z+IC0Rq}^_s-v4q|M|OH&@#QWlROp!;l@29)0Ua-C+zSn7@nOeOQWB1ol=OArgZHGk z;lq3Wl282L$@1laN2ci(&sT*z|Ef(0LNwgJ0-2Lca^W#F^DtoSjr1 zWAI$uUe+D=r`DSxJpa!pObzU~VlX5e3P=UtN4xK&KAc>X4I(EyBzj(f%+JWG%m#69 z3_kq4-@`K^4~A;~=q@2J36Ye>H8IH8+%)&UTClkRVwCPz!V8@_SU}}E_=+o3meFkx z$plCwT@EXfhM(^$pCv6V3oJnmZSCZ)RL`nzKgLGC$ZF3q_1NH1HR2}pkPj@39;; zvu7e-9=JGrGV61`G%(gQ)}uez(DA7F{eLPQTL53d6Av!@BZBPF)HE_Q#N~?%ZjEr5 zuQDUs4A0CY-VpKf@*+DE1=70o|3<=Roz<;wXMl+)zn}(9Aq)%4($^j3cAK-a`h4}Y|TuDu-{Bc*}5*GbwWm87St%`;UHW#wWwknfA zz4_a>J?#_pit-^F{UB|;n>yfkhr!LGrSTg$Fq7X&S4?RhA-A^2Zhk)X!-2_jm)O%O z)}&7z%0GFC(hHA5$!#0fLr3AS02H#TTcd{o4DezjdKfKNJs!To)MTRek>G&=GGg8- zH8bl2S;&ZA<~-M5CStGA#ZF1ZHSTK|aTrjWm2_f@%x&e@es$Aj!a`b#Rz=f6Z2Z+9 z%!mXWzz9ufw9gk0ujUgje%|Ch8+zDradUU35meLBYf$_{O1a58`w|Z{1C%@vU;u8X z1s05(0m^0&0T>yoPYxR_=*^!EYHy&*pC-Jj3_7HA)dOTgV5ADEqwTn=>aoPqn8a)! zvbP2lJ#3liVqTf*8?LOvYSCYcpwzMwn;ODmE!sm994S@o%-E>TTm0J94(bb>(ub(> zn&dAJpuC}+CH%kJX^)XQUf1gv7I~a(XjRqgjefpDObXF93})bDZ88u(-$wBVw;%-2 z0xS#I(nwRbr?7vWI6^?MnjeFi+-BR#cm8yaZ_SsZGy-QN5+R=N5Sl+KDd`Qg&u z{O}kM743xRto+-Ba5j5qM@QFn-}*BFZ8G+czhdbi+7!LDMSppIoBn$DKCzJMAsf-X z4_)$oAQ+XW!F$>H4IhGlR7F6LFCunUMacyTFPL*$_=`B$`~#_E<|DHAEI!q6AZqe& zAHLnZ{!L_CV&bZY152eqw{I?uO+T)Fe(PHJrr~w86;CFl^d9RUPLzrVsD-@-(sv{P z+yU>c<60cPp8Nd30C>xyG#g@i73N%-Y3?3kx&cfy7qH^@x}tL)u$W3MpXw%D#;e?s*+{x%7%At$)Pk17y5dgA!w6 zc=}DETo@V0o%152uy1#mq_Y`i)?-1^txI3;Pz~JmP;45bASX34fT8)kv1JUDfCI2o zs~7OF#dbk8e!ILu+W>(lT2pM&5}r zS*D%5?Bt3%UB^pe2PczIIH$tSxO7BFvdH7uNnEtFc3iErh;&5f zdG6oRIsNhc_51I4|E~LczkJ?)_pOw;MV!Cw+FTd^aXDxb4^Ww-;}xg(mrN3R*y<`QJ)% zVMA9DWtqP#*(&qsXVHD`6kmiAzwyDdIcVHPn-4$eJ15?ac@^rHQ!IyHxlt-f~wY*CJIo zOwhkhChqXT>0jNo_-H_HaBvVAZtI*{2{cxQw(E?%9b(cqno+6r)UKLmK5uH>pLdMW zz}6EJn86c54nYCmT;?`$u?c(cF85dqiw#j37y5kQvx{IhW@JgB?q2|s9x)} zxP7s_X;SSiA**dcCot8O8D5{Wt?Ay1Khf3BtW5t&Rylr#F=Z^9&X(&{O>u>$GY_Rx zw@w~l?OiyDOyiOc9qn{?8K4dft5ad- zOvaY8QNK*&?!s8>@e^2w{5=75vr7Ap+JxG<%z9*;{qnxdVT1sCd0gs6G)3gBCl6}J z6MN8RbMW*S7g>-YnN)l|UgWQwHn?{4T0bYCvVFXFaPrw>89#W=HiR+#hiaUQ=bda&n5aSy= zI}7;TDBQ7zGc6(JigELVz4SZr6KaFGuP~>X=Q8#(#k_EyIpKp%Dn?3fxr&`NXb5vo z#O41X0P!|}X4c9kbU+&G0W2tCvO&tIfa#AQ?kK2kwNN2H1~}Fr4|ZDD>r`k+**6_J z$>Eo|L(Vmme}={(d8wlaPPm|Xlt%&fLd??kYm$h2nkP*b{+y%M$%`zQ6_xrW{`@hSE|d+ zDa5tNVH>pN+S6$Z3w{S>ikpq@rcH@NW%jma#!l$G6qK8{EG3!-5w~<8gynt#$O*7? z#VCIn-rFV9f$gEVO8U&{U0M2dSTd$7BwL?TG7ndjR0Utvp(()t#@^>9XNtK`Znz^!qG?g(uo7E`gHK5u;hF z7pVK7hTxZ1Pmzv#{M^I(6scnL{!8p@NNJ>AKS+Pb^1E?j<||)XhieU{nZYDJ=%XV9 z;HlgfSGX|*;%~u!fVF}tY-)lpVYAQ8k=6Id|Unoq|-q~`lx*4`to*;Zd>ZqoSC5~8K#v%FKulTrxdXd$~$#`&7% zJNri-8IsB5#6uA+y@fbFD28tu4gEbpNwWvI0PR_YSw0=rJo$q5X*AJ2c&cSOwya^t z@6g?ZAhX87?2jrSoptjley>-W9{{emof9nm6Y0=J0#}F|6=DR8zCuWCu?ONnKlcaW zMv}-t<+RBM=%7)Ak>NWdC*SO6MRr>DP;3d5LX88ZUKC-+tgG((4+*PyJa91fbeID% zCpJ(d6z130n;B*fae^On%<;XCe3eZ3y}B$_`*{vkaG!#OC_SNl*#8}vSbSc{>E4K{F5+(#v~2cm=O%? zK*(ehvzvIhADae%Wq3DHq+p{sDgI*xW)# z|FfVw;FXYQVqG(a^8aMv+5lBHAeYH3CtJwD$=?;Q&6588ahqB*a7?PXNu5?4P&}la zRxBw(B?xK7X1g6LsZ>FU$QA(-*jS~RR>_QTBaN5f6}exqz$Jhs5Zwo8I5w&pPX~htnp^+>v%rdh{#w;pSdEV|_|kvXx6dTh?Y|!k R&WMD;0w{rgH+&=V{|B7HfR+FN literal 0 HcmV?d00001 From 2a9b28ddc313419a78e0c1ff971800d91ba624aa Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 3 Nov 2021 17:06:09 +0200 Subject: [PATCH 195/303] UI Improvement: added argument updatedData in function updateNode in nav-tree component --- ui-ngx/src/app/shared/components/nav-tree.component.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/shared/components/nav-tree.component.ts b/ui-ngx/src/app/shared/components/nav-tree.component.ts index afac4e78f4..7de7a8902f 100644 --- a/ui-ngx/src/app/shared/components/nav-tree.component.ts +++ b/ui-ngx/src/app/shared/components/nav-tree.component.ts @@ -42,7 +42,7 @@ export interface NavTreeEditCallbacks { nodeIsOpen?: (id: string) => boolean; nodeIsLoaded?: (id: string) => boolean; refreshNode?: (id: string) => void; - updateNode?: (id: string, newName: string) => void; + updateNode?: (id: string, newName: string, updatedData?: any) => void; createNode?: (parentId: string, node: NavTreeNode, pos: number | string) => void; deleteNode?: (id: string) => void; disableNode?: (id: string) => void; @@ -221,11 +221,14 @@ export class NavTreeComponent implements OnInit { } } }; - this.editCallbacks.updateNode = (id, newName) => { + this.editCallbacks.updateNode = (id, newName, updatedData) => { const node: NavTreeNode = this.treeElement.jstree('get_node', id); if (node) { this.treeElement.jstree('rename_node', node, newName); } + if (updatedData && node.data) { + Object.assign(node.data, updatedData); + } }; this.editCallbacks.createNode = (parentId, node, pos) => { const parentNode: NavTreeNode = this.treeElement.jstree('get_node', parentId); From 2aa7170dba056faf9dc6d55ec14dad5f2604ca9d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Nov 2021 17:12:05 +0200 Subject: [PATCH 196/303] Update swagger properties --- application/src/main/resources/thingsboard.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 40d9c105a1..6bc2dfbf9e 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -851,8 +851,8 @@ swagger: title: "${SWAGGER_TITLE:ThingsBoard REST API}" description: "${SWAGGER_DESCRIPTION: ThingsBoard open-source IoT platform REST API documentation.}" contact: - name: "${SWAGGER_CONTACT_NAME:Thingsboard team}" - url: "${SWAGGER_CONTACT_URL:http://thingsboard.io}" + name: "${SWAGGER_CONTACT_NAME:ThingsBoard team}" + url: "${SWAGGER_CONTACT_URL:https://thingsboard.io}" email: "${SWAGGER_CONTACT_EMAIL:info@thingsboard.io}" license: title: "${SWAGGER_LICENSE_TITLE:Apache License Version 2.0}" From d53d4362b7b8ac698ba4f22da9b0016bb6efad7d Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 3 Nov 2021 17:57:00 +0200 Subject: [PATCH 197/303] UI: Refactoring noDataDisplayMessageText --- .../widget/lib/alarms-table-widget.component.ts | 14 ++++++-------- .../widget/lib/entities-table-widget.component.ts | 14 ++++++-------- .../components/widget/lib/table-widget.models.ts | 10 ++++++++++ .../lib/timeseries-table-widget.component.html | 2 +- .../lib/timeseries-table-widget.component.ts | 5 +++++ .../home/components/widget/widget.component.ts | 11 ++++++----- .../home/models/dashboard-component.models.ts | 3 --- 7 files changed, 34 insertions(+), 25 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index d6d754f62b..7b32d84e71 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -39,7 +39,7 @@ import { createLabelFromDatasource, deepClone, hashCode, - isDefined, isNotEmptyStr, + isDefined, isNumber, isObject, isUndefined @@ -74,6 +74,7 @@ import { getColumnWidth, getRowStyleInfo, getTableCellButtonActions, + noDataMessage, prepareTableCellButtonActions, RowStyleInfo, TableCellButtonActionDescriptor, @@ -166,6 +167,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, public columns: Array = []; public displayedColumns: string[] = []; public alarmsDatasource: AlarmsDatasource; + public noDataDisplayMessageText: string; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -265,13 +267,6 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, } } - get noDataDisplayMessageText() { - const noDataDisplayMessage = this.ctx.widgetConfig.noDataDisplayMessage; - return isNotEmptyStr(noDataDisplayMessage) - ? this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage) - : this.translate.instant('alarm.no-alarms-prompt'); - } - ngAfterViewInit(): void { fromEvent(this.searchInputField.nativeElement, 'keyup') .pipe( @@ -364,6 +359,9 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.pageLink.severityList = isDefined(this.widgetConfig.alarmSeverityList) ? this.widgetConfig.alarmSeverityList : []; this.pageLink.typeList = isDefined(this.widgetConfig.alarmTypeList) ? this.widgetConfig.alarmTypeList : []; + this.noDataDisplayMessageText = + noDataMessage(this.widgetConfig.noDataDisplayMessage, 'alarm.no-alarms-prompt', this.utils, this.translate); + const cssString = constructTableCssString(this.widgetConfig); const cssParser = new cssjs(); cssParser.testMode = false; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index d068a1010e..bd52f2ab9b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -44,7 +44,7 @@ import { createLabelFromDatasource, deepClone, hashCode, - isDefined, isNotEmptyStr, + isDefined, isNumber, isObject, isUndefined @@ -80,6 +80,7 @@ import { getEntityValue, getRowStyleInfo, getTableCellButtonActions, + noDataMessage, prepareTableCellButtonActions, RowStyleInfo, TableCellButtonActionDescriptor, @@ -142,6 +143,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni public columns: Array = []; public displayedColumns: string[] = []; public entityDatasource: EntityDatasource; + public noDataDisplayMessageText: string; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -211,13 +213,6 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.ctx.updateWidgetParams(); } - get noDataDisplayMessageText() { - const noDataDisplayMessage = this.ctx.widgetConfig.noDataDisplayMessage; - return isNotEmptyStr(noDataDisplayMessage) - ? this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage) - : this.translate.instant('entity.no-entities-prompt'); - } - ngAfterViewInit(): void { fromEvent(this.searchInputField.nativeElement, 'keyup') .pipe( @@ -282,6 +277,9 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.pageSizeOptions = [this.defaultPageSize, this.defaultPageSize * 2, this.defaultPageSize * 3]; this.pageLink.pageSize = this.displayPagination ? this.defaultPageSize : 1024; + this.noDataDisplayMessageText = + noDataMessage(this.widgetConfig.noDataDisplayMessage, 'entity.no-entities-prompt', this.utils, this.translate); + const cssString = constructTableCssString(this.widgetConfig); const cssParser = new cssjs(); cssParser.testMode = false; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts index c18f467703..f90c287111 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts @@ -23,6 +23,8 @@ import { Direction, EntityDataSortOrder, EntityKey } from '@shared/models/query/ import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { WidgetContext } from '@home/models/widget-component.models'; import { FormattedData } from '@home/components/widget/lib/maps/map-models'; +import { UtilsService } from '@core/services/utils.service'; +import { TranslateService } from '@ngx-translate/core'; const tinycolor = tinycolor_; @@ -352,6 +354,14 @@ function filterTableCellButtonAction(widgetContext: WidgetContext, } } +export function noDataMessage(noDataDisplayMessage: string, defaultMessage: string, + utils: UtilsService, translate: TranslateService): string { + if (isNotEmptyStr(noDataDisplayMessage)) { + return utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage); + } + return translate.instant(defaultMessage); +} + export function constructTableCssString(widgetConfig: WidgetConfig): string { const origColor = widgetConfig.color || 'rgba(0, 0, 0, 0.87)'; const origBackgroundColor = widgetConfig.backgroundColor || 'rgb(255, 255, 255)'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html index 099820cfec..8c3b9084b0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html @@ -104,7 +104,7 @@ widget.no-data-found + class="no-data-found">{{ noDataDisplayMessageText }}
        = []; @@ -251,6 +253,9 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } this.pageSizeOptions = [this.defaultPageSize, this.defaultPageSize * 2, this.defaultPageSize * 3]; + this.noDataDisplayMessageText = + noDataMessage(this.widgetConfig.noDataDisplayMessage, 'widget.no-data-found', this.utils, this.translate); + let cssString = constructTableCssString(this.widgetConfig); const origBackgroundColor = this.widgetConfig.backgroundColor || 'rgb(255, 255, 255)'; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 257c7bd3a2..fb424f1645 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -141,6 +141,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI widgetErrorData: ExceptionData; loadingData: boolean; displayNoData = false; + noDataDisplayMessageText: string; displayLegend: boolean; legendConfig: LegendConfig; @@ -359,13 +360,13 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI setTimeout(() => { this.dashboardWidget.updateWidgetParams(); }, 0); - } - get noDataDisplayMessageText(): string { const noDataDisplayMessage = this.widget.config.noDataDisplayMessage; - return isNotEmptyStr(noDataDisplayMessage) - ? this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage) - : this.translate.instant('widget.no-data'); + if (isNotEmptyStr(noDataDisplayMessage)) { + this.noDataDisplayMessageText = this.utils.customTranslation(noDataDisplayMessage, noDataDisplayMessage); + } else { + this.noDataDisplayMessageText = this.translate.instant('widget.no-data'); + } } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index efbb3a5c23..2a3d92cf31 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -323,8 +323,6 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { dropShadow: boolean; enableFullscreen: boolean; - noDataDisplayMessage: string; - hasTimewindow: boolean; hasAggregation: boolean; @@ -413,7 +411,6 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { this.titleIcon = isDefined(this.widget.config.titleIcon) ? this.widget.config.titleIcon : ''; this.showTitleIcon = isDefined(this.widget.config.showTitleIcon) ? this.widget.config.showTitleIcon : false; - this.noDataDisplayMessage = isDefined(this.widget.config.noDataDisplayMessage) ? this.widget.config.noDataDisplayMessage : ''; this.titleIconStyle = {}; if (this.widget.config.iconColor) { this.titleIconStyle.color = this.widget.config.iconColor; From c76528245403c433eff200c793df46575cbb00c3 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Nov 2021 18:46:44 +0200 Subject: [PATCH 198/303] Update swagger version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ba162740c6..829f614e01 100755 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ 4.8.0 2.19.1 3.0.2 - 3.0.2 + 3.0.3 1.6.3 0.7 1.15.0 From 7f1559f17040102b68953f9a9caff7a4c39994bf Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Nov 2021 19:29:56 +0200 Subject: [PATCH 199/303] Fix swagger redirect --- .../main/java/org/thingsboard/server/config/WebConfig.java | 7 +++++-- docker/haproxy/config/haproxy.cfg | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/config/WebConfig.java b/application/src/main/java/org/thingsboard/server/config/WebConfig.java index e4a1eea01b..c20ec43fb7 100644 --- a/application/src/main/java/org/thingsboard/server/config/WebConfig.java +++ b/application/src/main/java/org/thingsboard/server/config/WebConfig.java @@ -17,7 +17,9 @@ package org.thingsboard.server.config; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +import org.thingsboard.server.utils.MiscUtils; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -30,8 +32,9 @@ public class WebConfig { } @RequestMapping("/swagger-ui.html") - public void redirectSwagger(HttpServletResponse response) throws IOException { - response.sendRedirect("/swagger-ui/"); + public void redirectSwagger(HttpServletRequest request, HttpServletResponse response) throws IOException { + String baseUrl = MiscUtils.constructBaseUrl(request); + response.sendRedirect(baseUrl + "/swagger-ui/"); } } diff --git a/docker/haproxy/config/haproxy.cfg b/docker/haproxy/config/haproxy.cfg index 50dcf36434..aa752502bf 100644 --- a/docker/haproxy/config/haproxy.cfg +++ b/docker/haproxy/config/haproxy.cfg @@ -69,7 +69,7 @@ frontend http-in acl transport_http_acl path_beg /api/v1/ acl letsencrypt_http_acl path_beg /.well-known/acme-challenge/ - acl tb_api_acl path_beg /api/ /swagger /webjars /v2/ /static/rulenode/ /oauth2/ /login/oauth2/ /static/widgets/ + acl tb_api_acl path_beg /api/ /swagger /webjars /v2/ /v3/ /static/rulenode/ /oauth2/ /login/oauth2/ /static/widgets/ redirect scheme https if !letsencrypt_http_acl !transport_http_acl { env(FORCE_HTTPS_REDIRECT) -m str true } @@ -87,7 +87,7 @@ frontend https_in http-request add-header "X-Forwarded-Proto" "https" acl transport_http_acl path_beg /api/v1/ - acl tb_api_acl path_beg /api/ /swagger /webjars /v2/ /static/rulenode/ /oauth2/ /login/oauth2/ /static/widgets/ + acl tb_api_acl path_beg /api/ /swagger /webjars /v2/ /v3/ /static/rulenode/ /oauth2/ /login/oauth2/ /static/widgets/ use_backend tb-http-backend if transport_http_acl use_backend tb-api-backend if tb_api_acl From cd23b85baa056558dc97b6fba8b617e623ece220 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 4 Nov 2021 11:15:44 +0200 Subject: [PATCH 200/303] Bump hsqldb version to 2.6.1 to fix sql timeout issues --- .../java/org/thingsboard/server/controller/BaseController.java | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 0943ef27d1..6a5c7ae539 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -314,7 +314,7 @@ public abstract class BaseController { } else if (exception instanceof MessagingException) { return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); } else { - return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.GENERAL); + return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL); } } diff --git a/pom.xml b/pom.xml index 829f614e01..1c73f6b919 100755 --- a/pom.xml +++ b/pom.xml @@ -121,7 +121,7 @@ 4.1.0 4.3.1.0 2.7.2 - 2.6.0 + 2.6.1 1.5.2 5.6.3 2.6.0 From fe5215c7ccb6df14ae34fe81a07c4f61c164b8ce Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Thu, 4 Nov 2021 12:55:23 +0200 Subject: [PATCH 201/303] Minor refactoring --- .../java/org/thingsboard/server/controller/AdminController.java | 1 - .../thingsboard/server/controller/EntityRelationController.java | 2 -- .../server/exception/ThingsboardErrorResponseHandler.java | 1 + .../thingsboard/server/dao/relation/BaseRelationService.java | 2 ++ 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AdminController.java b/application/src/main/java/org/thingsboard/server/controller/AdminController.java index 1fbd52d8e3..d9a8f436b9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AdminController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AdminController.java @@ -103,7 +103,6 @@ public class AdminController extends BaseController { } else if (adminSettings.getKey().equals("sms")) { smsService.updateSmsConfiguration(); } - return adminSettings; } catch (Exception e) { throw handleException(e); diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 7131fc0edf..f5c5bdd284 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -37,7 +37,6 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.RelationTypeGroup; -import org.thingsboard.server.dao.service.ConstraintValidator; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; @@ -85,7 +84,6 @@ public class EntityRelationController extends BaseController { if (relation.getTypeGroup() == null) { relation.setTypeGroup(RelationTypeGroup.COMMON); } - ConstraintValidator.validateFields(relation); relationService.saveRelation(getTenantId(), relation); logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java index e656dc1d88..906e87d608 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java @@ -95,6 +95,7 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand } } + private void handleThingsboardException(ThingsboardException thingsboardException, HttpServletResponse response) throws IOException { ThingsboardErrorCode errorCode = thingsboardException.getErrorCode(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index b577022d57..2be2331a99 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.service.ConstraintValidator; import javax.annotation.Nullable; import java.util.ArrayList; @@ -559,6 +560,7 @@ public class BaseRelationService implements RelationService { if (relation == null) { throw new DataValidationException("Relation type should be specified!"); } + ConstraintValidator.validateFields(relation); validate(relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup()); } From 22ce8cf06304d3bd7c5bfac46be395ede579a4bc Mon Sep 17 00:00:00 2001 From: Swoq Date: Thu, 9 Sep 2021 15:22:19 +0300 Subject: [PATCH 202/303] Fix upgrade from version 3.2.2 --- .../service/install/update/DefaultDataUpdateService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index ebe727b6da..06df7164df 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -153,12 +153,16 @@ public class DefaultDataUpdateService implements DataUpdateService { JsonNode createRules = node.get("createRules"); for (AlarmSeverity severity : AlarmSeverity.values()) { if (createRules.has(severity.name())) { - isUpdated = isUpdated || convertDeviceProfileAlarmRulesForVersion330(createRules.get(severity.name()).get("condition").get("spec")); + JsonNode spec = createRules.get(severity.name()).get("condition").get("spec"); + boolean convertResult = convertDeviceProfileAlarmRulesForVersion330(spec); + isUpdated = convertResult || isUpdated; } } } if (node.has("clearRule") && !node.get("clearRule").isNull()) { - isUpdated = isUpdated || convertDeviceProfileAlarmRulesForVersion330(node.get("clearRule").get("condition").get("spec")); + JsonNode spec = node.get("clearRule").get("condition").get("spec"); + boolean convertResult = convertDeviceProfileAlarmRulesForVersion330(spec); + isUpdated = convertResult || isUpdated; } } if (isUpdated) { From 5599ab56505ebbb9370e3f71de239d186b2a9072 Mon Sep 17 00:00:00 2001 From: Swoq Date: Mon, 13 Sep 2021 18:03:10 +0300 Subject: [PATCH 203/303] Refactoring Device Profile upgrade --- .../update/DefaultDataUpdateService.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 06df7164df..98ff983607 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -147,22 +147,22 @@ public class DefaultDataUpdateService implements DataUpdateService { if (deviceProfile.getProfileData().has("alarms") && !deviceProfile.getProfileData().get("alarms").isNull()) { boolean isUpdated = false; - JsonNode array = deviceProfile.getProfileData().get("alarms"); - for (JsonNode node : array) { - if (node.has("createRules")) { - JsonNode createRules = node.get("createRules"); + JsonNode alarms = deviceProfile.getProfileData().get("alarms"); + for (JsonNode alarm : alarms) { + if (alarm.has("createRules")) { + JsonNode createRules = alarm.get("createRules"); for (AlarmSeverity severity : AlarmSeverity.values()) { if (createRules.has(severity.name())) { JsonNode spec = createRules.get(severity.name()).get("condition").get("spec"); - boolean convertResult = convertDeviceProfileAlarmRulesForVersion330(spec); - isUpdated = convertResult || isUpdated; + if (convertDeviceProfileAlarmRulesForVersion330(spec)) + isUpdated = true; } } } - if (node.has("clearRule") && !node.get("clearRule").isNull()) { - JsonNode spec = node.get("clearRule").get("condition").get("spec"); - boolean convertResult = convertDeviceProfileAlarmRulesForVersion330(spec); - isUpdated = convertResult || isUpdated; + if (alarm.has("clearRule") && !alarm.get("clearRule").isNull()) { + JsonNode spec = alarm.get("clearRule").get("condition").get("spec"); + if (convertDeviceProfileAlarmRulesForVersion330(spec)) + isUpdated = true; } } if (isUpdated) { From e18d83446175c1569cfc5de232ad53b44c5c6dc5 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 4 Nov 2021 13:07:05 +0200 Subject: [PATCH 204/303] Code style improvements --- .../service/install/update/DefaultDataUpdateService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 98ff983607..3172c37af6 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -154,15 +154,17 @@ public class DefaultDataUpdateService implements DataUpdateService { for (AlarmSeverity severity : AlarmSeverity.values()) { if (createRules.has(severity.name())) { JsonNode spec = createRules.get(severity.name()).get("condition").get("spec"); - if (convertDeviceProfileAlarmRulesForVersion330(spec)) + if (convertDeviceProfileAlarmRulesForVersion330(spec)) { isUpdated = true; + } } } } if (alarm.has("clearRule") && !alarm.get("clearRule").isNull()) { JsonNode spec = alarm.get("clearRule").get("condition").get("spec"); - if (convertDeviceProfileAlarmRulesForVersion330(spec)) + if (convertDeviceProfileAlarmRulesForVersion330(spec)) { isUpdated = true; + } } } if (isUpdated) { From d78c1b2de42c98dbddf642cd58f3383f71f59a82 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Thu, 4 Nov 2021 13:15:13 +0200 Subject: [PATCH 205/303] Update TbRuleEngineProcessingStrategyFactory.java --- .../processing/TbRuleEngineProcessingStrategyFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java index 2749dd7fc5..a94731696f 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java @@ -78,7 +78,7 @@ public class TbRuleEngineProcessingStrategyFactory { @Override public TbRuleEngineProcessingDecision analyze(TbRuleEngineProcessingResult result) { if (result.isSuccess()) { - log.debug("[{}] The result of the msg pack processing is successful, going to proceed with processing of the following msgs", queueName); + log.trace("[{}] The result of the msg pack processing is successful, going to proceed with processing of the following msgs", queueName); return new TbRuleEngineProcessingDecision(true, null); } else { if (retryCount == 0) { @@ -107,8 +107,8 @@ public class TbRuleEngineProcessingStrategyFactory { } if (retrySuccessful) { result.getSuccessMap().forEach(toReprocess::put); - } else if (log.isDebugEnabled() && !result.getSuccessMap().isEmpty()) { - log.debug("[{}] Skipped {} successful messages due to the processing strategy configuration", queueName, result.getSuccessMap().size()); + } else if (log.isTraceEnabled() && !result.getSuccessMap().isEmpty()) { + log.trace("[{}] Skipped {} successful messages due to the processing strategy configuration", queueName, result.getSuccessMap().size()); } if (CollectionUtils.isEmpty(toReprocess)) { if (log.isDebugEnabled()) { From ab0ad885ab9c810a2d496867ae6238c8185a9494 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Mon, 1 Nov 2021 15:38:14 +0200 Subject: [PATCH 206/303] Entities text search by substring in JPA repositories --- .../server/dao/sql/alarm/AlarmRepository.java | 42 +++++++++---------- .../server/dao/sql/asset/AssetRepository.java | 20 ++++----- .../dao/sql/audit/AuditLogRepository.java | 36 ++++++++-------- .../ComponentDescriptorRepository.java | 4 +- .../dao/sql/customer/CustomerRepository.java | 2 +- .../dashboard/DashboardInfoRepository.java | 10 ++--- .../sql/device/DeviceProfileRepository.java | 6 +-- .../dao/sql/device/DeviceRepository.java | 30 ++++++------- .../dao/sql/edge/EdgeEventRepository.java | 4 +- .../server/dao/sql/edge/EdgeRepository.java | 18 ++++---- .../sql/entityview/EntityViewRepository.java | 20 ++++----- .../server/dao/sql/event/EventRepository.java | 2 +- .../dao/sql/ota/OtaPackageInfoRepository.java | 4 +- .../dao/sql/rule/RuleChainRepository.java | 8 ++-- .../sql/tenant/TenantProfileRepository.java | 4 +- .../dao/sql/tenant/TenantRepository.java | 4 +- .../server/dao/sql/user/UserRepository.java | 4 +- .../sql/widget/WidgetsBundleRepository.java | 6 +-- 18 files changed, 112 insertions(+), 112 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index 8f862390c3..a67e29bac0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -52,9 +52,9 @@ public interface AlarmRepository extends CrudRepository { "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " , countQuery = "" + "SELECT count(a) + " + //alarms with relations only @@ -70,9 +70,9 @@ public interface AlarmRepository extends CrudRepository { " AND (:startTime IS NULL OR a.createdTime >= :startTime) " + " AND (:endTime IS NULL OR a.createdTime <= :endTime) " + " AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - " AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) " + + " AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " + " )" + "FROM AlarmEntity a " + "INNER JOIN RelationEntity re ON a.id = re.toId " + @@ -84,9 +84,9 @@ public interface AlarmRepository extends CrudRepository { "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) ") + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") Page findAlarms(@Param("tenantId") UUID tenantId, @Param("affectedEntityId") UUID affectedEntityId, @Param("affectedEntityType") String affectedEntityType, @@ -101,9 +101,9 @@ public interface AlarmRepository extends CrudRepository { "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) ", + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ", countQuery = "" + "SELECT count(a) " + "FROM AlarmEntity a " + @@ -111,9 +111,9 @@ public interface AlarmRepository extends CrudRepository { "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) ") + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") Page findAllAlarms(@Param("tenantId") UUID tenantId, @Param("startTime") Long startTime, @Param("endTime") Long endTime, @@ -126,9 +126,9 @@ public interface AlarmRepository extends CrudRepository { "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " , countQuery = "" + "SELECT count(a) " + @@ -137,9 +137,9 @@ public interface AlarmRepository extends CrudRepository { "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) ") + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") Page findCustomerAlarms(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("startTime") Long startTime, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java index 89d1006018..8a61447a00 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java @@ -39,7 +39,7 @@ public interface AssetRepository extends PagingAndSortingRepository findByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @@ -48,14 +48,14 @@ public interface AssetRepository extends PagingAndSortingRepository findAssetInfosByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT a FROM AssetEntity a WHERE a.tenantId = :tenantId " + "AND a.customerId = :customerId " + - "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(a.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("textSearch") String textSearch, @@ -66,7 +66,7 @@ public interface AssetRepository extends PagingAndSortingRepository findAssetInfosByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -80,7 +80,7 @@ public interface AssetRepository extends PagingAndSortingRepository findByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -91,7 +91,7 @@ public interface AssetRepository extends PagingAndSortingRepository findAssetInfosByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -100,7 +100,7 @@ public interface AssetRepository extends PagingAndSortingRepository findByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("type") String type, @@ -113,7 +113,7 @@ public interface AssetRepository extends PagingAndSortingRepository findAssetInfosByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("type") String type, @@ -126,7 +126,7 @@ public interface AssetRepository extends PagingAndSortingRepository findByTenantIdAndEdgeId(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @Param("searchText") String searchText, @@ -136,7 +136,7 @@ public interface AssetRepository extends PagingAndSortingRepository findByTenantIdAndEdgeIdAndType(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @Param("type") String type, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/audit/AuditLogRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/audit/AuditLogRepository.java index a574cb1581..b0291749d6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/audit/AuditLogRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/audit/AuditLogRepository.java @@ -34,11 +34,11 @@ public interface AuditLogRepository extends PagingAndSortingRepository= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:actionTypes) IS NULL OR a.actionType in (:actionTypes)) " + - "AND (LOWER(a.entityType) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.entityName) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.userName) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.actionType) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.actionStatus) LIKE LOWER(CONCAT(:textSearch, '%')))" + "AND (LOWER(a.entityType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.entityName) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.userName) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.actionType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.actionStatus) LIKE LOWER(CONCAT('%', :textSearch, '%')))" ) Page findByTenantId( @Param("tenantId") UUID tenantId, @@ -54,10 +54,10 @@ public interface AuditLogRepository extends PagingAndSortingRepository= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:actionTypes) IS NULL OR a.actionType in (:actionTypes)) " + - "AND (LOWER(a.entityName) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.userName) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.actionType) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.actionStatus) LIKE LOWER(CONCAT(:textSearch, '%')))" + "AND (LOWER(a.entityName) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.userName) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.actionType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.actionStatus) LIKE LOWER(CONCAT('%', :textSearch, '%')))" ) Page findAuditLogsByTenantIdAndEntityId(@Param("tenantId") UUID tenantId, @Param("entityType") EntityType entityType, @@ -74,11 +74,11 @@ public interface AuditLogRepository extends PagingAndSortingRepository= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:actionTypes) IS NULL OR a.actionType in (:actionTypes)) " + - "AND (LOWER(a.entityType) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.entityName) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.userName) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.actionType) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.actionStatus) LIKE LOWER(CONCAT(:textSearch, '%')))" + "AND (LOWER(a.entityType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.entityName) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.userName) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.actionType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.actionStatus) LIKE LOWER(CONCAT('%', :textSearch, '%')))" ) Page findAuditLogsByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @@ -94,10 +94,10 @@ public interface AuditLogRepository extends PagingAndSortingRepository= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:actionTypes) IS NULL OR a.actionType in (:actionTypes)) " + - "AND (LOWER(a.entityType) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.entityName) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.actionType) LIKE LOWER(CONCAT(:textSearch, '%'))" + - "OR LOWER(a.actionStatus) LIKE LOWER(CONCAT(:textSearch, '%')))" + "AND (LOWER(a.entityType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.entityName) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.actionType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" + + "OR LOWER(a.actionStatus) LIKE LOWER(CONCAT('%', :textSearch, '%')))" ) Page findAuditLogsByTenantIdAndUserId(@Param("tenantId") UUID tenantId, @Param("userId") UUID userId, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/component/ComponentDescriptorRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/component/ComponentDescriptorRepository.java index 115a78068d..5f2621ed11 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/component/ComponentDescriptorRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/component/ComponentDescriptorRepository.java @@ -34,13 +34,13 @@ public interface ComponentDescriptorRepository extends PagingAndSortingRepositor ComponentDescriptorEntity findByClazz(String clazz); @Query("SELECT cd FROM ComponentDescriptorEntity cd WHERE cd.type = :type " + - "AND LOWER(cd.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(cd.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByType(@Param("type") ComponentType type, @Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT cd FROM ComponentDescriptorEntity cd WHERE cd.type = :type " + - "AND cd.scope = :scope AND LOWER(cd.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND cd.scope = :scope AND LOWER(cd.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByScopeAndType(@Param("type") ComponentType type, @Param("scope") ComponentScope scope, @Param("textSearch") String textSearch, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java index d91563917f..fb8005250b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java @@ -30,7 +30,7 @@ import java.util.UUID; public interface CustomerRepository extends PagingAndSortingRepository { @Query("SELECT c FROM CustomerEntity c WHERE c.tenantId = :tenantId " + - "AND LOWER(c.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(c.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java index b913164d03..68b33c59fd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java @@ -32,14 +32,14 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository findByTenantId(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); @Query("SELECT di FROM DashboardInfoEntity di WHERE di.tenantId = :tenantId " + "AND di.mobileHide = false " + - "AND LOWER(di.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(di.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findMobileByTenantId(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); @@ -47,7 +47,7 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository findByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -57,7 +57,7 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository findMobileByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -66,7 +66,7 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository findByTenantIdAndEdgeId(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @Param("searchText") String searchText, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java index 311c73100c..5e2155f34f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java @@ -35,21 +35,21 @@ public interface DeviceProfileRepository extends JpaRepository findDeviceProfiles(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.defaultDashboardId, d.type, d.transportType) " + "FROM DeviceProfileEntity d WHERE " + - "d.tenantId = :tenantId AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "d.tenantId = :tenantId AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findDeviceProfileInfos(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.defaultDashboardId, d.type, d.transportType) " + "FROM DeviceProfileEntity d WHERE " + - "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findDeviceProfileInfos(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, @Param("transportType") DeviceTransportType transportType, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java index 8296dc9bf3..2deae0bbe1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java @@ -42,7 +42,7 @@ public interface DeviceRepository extends JpaRepository { @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + "AND d.customerId = :customerId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -50,7 +50,7 @@ public interface DeviceRepository extends JpaRepository { @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + "AND d.deviceProfileId = :profileId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findByTenantIdAndProfileId(@Param("tenantId") UUID tenantId, @Param("profileId") UUID profileId, @Param("searchText") String searchText, @@ -62,7 +62,7 @@ public interface DeviceRepository extends JpaRepository { "LEFT JOIN DeviceProfileEntity p on p.id = d.deviceProfileId " + "WHERE d.tenantId = :tenantId " + "AND d.customerId = :customerId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findDeviceInfosByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -73,7 +73,7 @@ public interface DeviceRepository extends JpaRepository { Pageable pageable); @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @@ -83,14 +83,14 @@ public interface DeviceRepository extends JpaRepository { "LEFT JOIN CustomerEntity c on c.id = d.customerId " + "LEFT JOIN DeviceProfileEntity p on p.id = d.deviceProfileId " + "WHERE d.tenantId = :tenantId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findDeviceInfosByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + "AND d.type = :type " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -99,7 +99,7 @@ public interface DeviceRepository extends JpaRepository { @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + "AND d.deviceProfileId = :deviceProfileId " + "AND d.firmwareId = null " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantIdAndTypeAndFirmwareIdIsNull(@Param("tenantId") UUID tenantId, @Param("deviceProfileId") UUID deviceProfileId, @Param("textSearch") String textSearch, @@ -108,7 +108,7 @@ public interface DeviceRepository extends JpaRepository { @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + "AND d.deviceProfileId = :deviceProfileId " + "AND d.softwareId = null " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantIdAndTypeAndSoftwareIdIsNull(@Param("tenantId") UUID tenantId, @Param("deviceProfileId") UUID deviceProfileId, @Param("textSearch") String textSearch, @@ -132,7 +132,7 @@ public interface DeviceRepository extends JpaRepository { "LEFT JOIN DeviceProfileEntity p on p.id = d.deviceProfileId " + "WHERE d.tenantId = :tenantId " + "AND d.type = :type " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findDeviceInfosByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -144,7 +144,7 @@ public interface DeviceRepository extends JpaRepository { "LEFT JOIN DeviceProfileEntity p on p.id = d.deviceProfileId " + "WHERE d.tenantId = :tenantId " + "AND d.deviceProfileId = :deviceProfileId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findDeviceInfosByTenantIdAndDeviceProfileId(@Param("tenantId") UUID tenantId, @Param("deviceProfileId") UUID deviceProfileId, @Param("textSearch") String textSearch, @@ -153,7 +153,7 @@ public interface DeviceRepository extends JpaRepository { @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + "AND d.customerId = :customerId " + "AND d.type = :type " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("type") String type, @@ -167,7 +167,7 @@ public interface DeviceRepository extends JpaRepository { "WHERE d.tenantId = :tenantId " + "AND d.customerId = :customerId " + "AND d.type = :type " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findDeviceInfosByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("type") String type, @@ -181,7 +181,7 @@ public interface DeviceRepository extends JpaRepository { "WHERE d.tenantId = :tenantId " + "AND d.customerId = :customerId " + "AND d.deviceProfileId = :deviceProfileId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findDeviceInfosByTenantIdAndCustomerIdAndDeviceProfileId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("deviceProfileId") UUID deviceProfileId, @@ -204,7 +204,7 @@ public interface DeviceRepository extends JpaRepository { @Query("SELECT d FROM DeviceEntity d, RelationEntity re WHERE d.tenantId = :tenantId " + "AND d.id = re.toId AND re.toType = 'DEVICE' AND re.relationTypeGroup = 'EDGE' " + "AND re.relationType = 'Contains' AND re.fromId = :edgeId AND re.fromType = 'EDGE' " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findByTenantIdAndEdgeId(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @Param("searchText") String searchText, @@ -214,7 +214,7 @@ public interface DeviceRepository extends JpaRepository { "AND d.id = re.toId AND re.toType = 'DEVICE' AND re.relationTypeGroup = 'EDGE' " + "AND re.relationType = 'Contains' AND re.fromId = :edgeId AND re.fromType = 'EDGE' " + "AND d.type = :type " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findByTenantIdAndEdgeIdAndType(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @Param("type") String type, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java index 24b4084e1f..48aaffb96e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java @@ -32,7 +32,7 @@ public interface EdgeEventRepository extends PagingAndSortingRepository= :startTime) " + "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + - "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT(:textSearch, '%'))" + "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" ) Page findEdgeEventsByTenantIdAndEdgeId(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @@ -47,7 +47,7 @@ public interface EdgeEventRepository extends PagingAndSortingRepository= :startTime) " + "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + "AND e.edgeEventAction <> 'TIMESERIES_UPDATED' " + - "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT(:textSearch, '%'))" + "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" ) Page findEdgeEventsByTenantIdAndEdgeIdWithoutTimeseriesUpdated(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java index f12dda790d..cd0fcd8933 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java @@ -31,7 +31,7 @@ public interface EdgeRepository extends PagingAndSortingRepository findByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("textSearch") String textSearch, @@ -44,7 +44,7 @@ public interface EdgeRepository extends PagingAndSortingRepository findByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @@ -53,14 +53,14 @@ public interface EdgeRepository extends PagingAndSortingRepository findEdgeInfosByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " + "AND d.type = :type " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -71,7 +71,7 @@ public interface EdgeRepository extends PagingAndSortingRepository findEdgeInfosByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -80,7 +80,7 @@ public interface EdgeRepository extends PagingAndSortingRepository findByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("type") String type, @@ -92,7 +92,7 @@ public interface EdgeRepository extends PagingAndSortingRepository findEdgeInfosByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -104,7 +104,7 @@ public interface EdgeRepository extends PagingAndSortingRepository findEdgeInfosByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("type") String type, @@ -114,7 +114,7 @@ public interface EdgeRepository extends PagingAndSortingRepository findByTenantIdAndEntityId(@Param("tenantId") UUID tenantId, @Param("entityId") UUID entityId, @Param("entityType") String entityType, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java index 9e33b6e701..45c5886d7c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java @@ -39,7 +39,7 @@ public interface EntityViewRepository extends PagingAndSortingRepository findByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @@ -48,14 +48,14 @@ public interface EntityViewRepository extends PagingAndSortingRepository findEntityViewInfosByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + "AND e.type = :type " + - "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(e.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -66,7 +66,7 @@ public interface EntityViewRepository extends PagingAndSortingRepository findEntityViewInfosByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -74,7 +74,7 @@ public interface EntityViewRepository extends PagingAndSortingRepository findByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -85,7 +85,7 @@ public interface EntityViewRepository extends PagingAndSortingRepository findEntityViewInfosByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -94,7 +94,7 @@ public interface EntityViewRepository extends PagingAndSortingRepository findByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("type") String type, @@ -107,7 +107,7 @@ public interface EntityViewRepository extends PagingAndSortingRepository findEntityViewInfosByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("type") String type, @@ -124,7 +124,7 @@ public interface EntityViewRepository extends PagingAndSortingRepository findByTenantIdAndEdgeId(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @Param("searchText") String searchText, @@ -134,7 +134,7 @@ public interface EntityViewRepository extends PagingAndSortingRepository findByTenantIdAndEdgeIdAndType(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @Param("type") String type, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java index 270ab26329..84d2a484e1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java @@ -55,7 +55,7 @@ public interface EventRepository extends PagingAndSortingRepository= :startTime) " + "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + - "AND LOWER(e.eventType) LIKE LOWER(CONCAT(:textSearch, '%'))" + "AND LOWER(e.eventType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" ) Page findEventsByTenantIdAndEntityId(@Param("tenantId") UUID tenantId, @Param("entityType") EntityType entityType, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/OtaPackageInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/OtaPackageInfoRepository.java index 112b6dd222..3e60afa595 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/OtaPackageInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/OtaPackageInfoRepository.java @@ -28,7 +28,7 @@ import java.util.UUID; public interface OtaPackageInfoRepository extends CrudRepository { @Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.tag, f.url, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, CASE WHEN (f.data IS NOT NULL OR f.url IS NOT NULL) THEN true ELSE false END) FROM OtaPackageEntity f WHERE " + "f.tenantId = :tenantId " + - "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(f.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findAllByTenantId(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); @@ -38,7 +38,7 @@ public interface OtaPackageInfoRepository extends CrudRepository findAllByTenantIdAndTypeAndDeviceProfileIdAndHasData(@Param("tenantId") UUID tenantId, @Param("deviceProfileId") UUID deviceProfileId, @Param("type") OtaPackageType type, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java index fda0a0d7f0..750b59e363 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java @@ -29,14 +29,14 @@ import java.util.UUID; public interface RuleChainRepository extends PagingAndSortingRepository { @Query("SELECT rc FROM RuleChainEntity rc WHERE rc.tenantId = :tenantId " + - "AND LOWER(rc.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(rc.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findByTenantId(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); @Query("SELECT rc FROM RuleChainEntity rc WHERE rc.tenantId = :tenantId " + "AND rc.type = :type " + - "AND LOWER(rc.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") + "AND LOWER(rc.searchText) LIKE LOWER(CONCAT('%', :searchText, '%'))") Page findByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") RuleChainType type, @Param("searchText") String searchText, @@ -45,7 +45,7 @@ public interface RuleChainRepository extends PagingAndSortingRepository findByTenantIdAndEdgeId(@Param("tenantId") UUID tenantId, @Param("edgeId") UUID edgeId, @Param("searchText") String searchText, @@ -54,7 +54,7 @@ public interface RuleChainRepository extends PagingAndSortingRepository findAutoAssignByTenantId(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantProfileRepository.java index 523d524f6c..a1a6603c9a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantProfileRepository.java @@ -33,13 +33,13 @@ public interface TenantProfileRepository extends PagingAndSortingRepository findTenantProfiles(@Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT new org.thingsboard.server.common.data.EntityInfo(t.id, 'TENANT_PROFILE', t.name) " + "FROM TenantProfileEntity t " + - "WHERE LOWER(t.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "WHERE LOWER(t.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findTenantProfileInfos(@Param("textSearch") String textSearch, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java index 8ab12e0bb5..4fc4b04885 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java @@ -37,7 +37,7 @@ public interface TenantRepository extends PagingAndSortingRepository findByRegionNextPage(@Param("region") String region, @Param("textSearch") String textSearch, Pageable pageable); @@ -46,7 +46,7 @@ public interface TenantRepository extends PagingAndSortingRepository findTenantInfoByRegionNextPage(@Param("region") String region, @Param("textSearch") String textSearch, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java index 32357ff921..477b7e8892 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java @@ -34,7 +34,7 @@ public interface UserRepository extends PagingAndSortingRepository findUsersByAuthority(@Param("tenantId") UUID tenantId, @Param("customerId") UUID customerId, @Param("searchText") String searchText, @@ -42,7 +42,7 @@ public interface UserRepository extends PagingAndSortingRepository findByTenantId(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java index 5a3bb8b973..2b6abd5dac 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java @@ -32,19 +32,19 @@ public interface WidgetsBundleRepository extends PagingAndSortingRepository findSystemWidgetsBundles(@Param("systemTenantId") UUID systemTenantId, @Param("searchText") String searchText, Pageable pageable); @Query("SELECT wb FROM WidgetsBundleEntity wb WHERE wb.tenantId = :tenantId " + - "AND LOWER(wb.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(wb.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findTenantWidgetsBundlesByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @Query("SELECT wb FROM WidgetsBundleEntity wb WHERE wb.tenantId IN (:tenantId, :nullTenantId) " + - "AND LOWER(wb.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") + "AND LOWER(wb.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findAllTenantWidgetsBundlesByTenantId(@Param("tenantId") UUID tenantId, @Param("nullTenantId") UUID nullTenantId, @Param("textSearch") String textSearch, From 7c2b3a9fbf84cc58aa7546029c5c7c10a662c55a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 4 Nov 2021 15:26:36 +0200 Subject: [PATCH 207/303] Improve REST API error response handling. Update swagger api. --- application/pom.xml | 11 +++ .../server/config/SwaggerConfiguration.java | 11 ++- .../server/controller/AdminController.java | 2 +- .../server/controller/BaseController.java | 70 ++++++++------- .../server/controller/CustomerController.java | 2 +- .../controller/DashboardController.java | 5 ++ .../ThingsboardErrorResponseHandler.java | 84 ++++++++++++------ .../src/main/resources/thingsboard.yml | 7 +- .../server/common/data/AdminSettings.java | 2 +- pom.xml | 2 +- transport/lwm2m/src/main/data/lwm2mserver.jks | Bin 3953 -> 3849 bytes 11 files changed, 133 insertions(+), 63 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index fd90d00d34..cc3bcef183 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -339,6 +339,17 @@ ${project.basedir}/src/main/resources + true + + thingsboard.yml + + + + ${project.basedir}/src/main/resources + false + + thingsboard.yml + diff --git a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java index 25cc862924..2927aff3f0 100644 --- a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java @@ -26,10 +26,12 @@ import org.springframework.core.annotation.Order; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.exception.ThingsboardCredentialsExpiredResponse; import org.thingsboard.server.exception.ThingsboardErrorResponse; +import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.auth.rest.LoginRequest; import org.thingsboard.server.service.security.auth.rest.LoginResponse; import springfox.documentation.builders.ApiInfoBuilder; @@ -81,6 +83,7 @@ import static springfox.documentation.builders.PathSelectors.regex; @Slf4j @Configuration +@TbCoreComponent public class SwaggerConfiguration { @Value("${swagger.api_path_regex}") @@ -105,6 +108,8 @@ public class SwaggerConfiguration { private String licenseUrl; @Value("${swagger.version}") private String version; + @Value("${app.version:unknown}") + private String appVersion; @Bean public Docket thingsboardApi() { @@ -231,13 +236,17 @@ public class SwaggerConfiguration { } private ApiInfo apiInfo() { + String apiVersion = version; + if (StringUtils.isEmpty(apiVersion)) { + apiVersion = appVersion; + } return new ApiInfoBuilder() .title(title) .description(description) .contact(new Contact(contactName, contactUrl, contactEmail)) .license(licenseTitle) .licenseUrl(licenseUrl) - .version(version) + .version(apiVersion) .build(); } diff --git a/application/src/main/java/org/thingsboard/server/controller/AdminController.java b/application/src/main/java/org/thingsboard/server/controller/AdminController.java index d9a8f436b9..c339d8d49e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AdminController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AdminController.java @@ -73,7 +73,7 @@ public class AdminController extends BaseController { @PathVariable("key") String key) throws ThingsboardException { try { accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ); - AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key)); + AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key), "No Administration settings found for key: " + key); if (adminSettings.getKey().equals("mail")) { ((ObjectNode) adminSettings.getJsonValue()).remove("password"); } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 6a5c7ae539..a6ebaa4c99 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -319,17 +319,25 @@ public abstract class BaseController { } T checkNotNull(T reference) throws ThingsboardException { + return checkNotNull(reference, "Requested item wasn't found!"); + } + + T checkNotNull(T reference, String notFoundMessage) throws ThingsboardException { if (reference == null) { - throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); + throw new ThingsboardException(notFoundMessage, ThingsboardErrorCode.ITEM_NOT_FOUND); } return reference; } T checkNotNull(Optional reference) throws ThingsboardException { + return checkNotNull(reference, "Requested item wasn't found!"); + } + + T checkNotNull(Optional reference, String notFoundMessage) throws ThingsboardException { if (reference.isPresent()) { return reference.get(); } else { - throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); + throw new ThingsboardException(notFoundMessage, ThingsboardErrorCode.ITEM_NOT_FOUND); } } @@ -389,7 +397,7 @@ public abstract class BaseController { try { validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Tenant tenant = tenantService.findTenantById(tenantId); - checkNotNull(tenant); + checkNotNull(tenant, "Tenant with id [" + tenantId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.TENANT, operation, tenantId, tenant); return tenant; } catch (Exception e) { @@ -401,7 +409,7 @@ public abstract class BaseController { try { validateId(tenantId, INCORRECT_TENANT_ID + tenantId); TenantInfo tenant = tenantService.findTenantInfoById(tenantId); - checkNotNull(tenant); + checkNotNull(tenant, "Tenant with id [" + tenantId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.TENANT, operation, tenantId, tenant); return tenant; } catch (Exception e) { @@ -413,7 +421,7 @@ public abstract class BaseController { try { validateId(tenantProfileId, "Incorrect tenantProfileId " + tenantProfileId); TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(getTenantId(), tenantProfileId); - checkNotNull(tenantProfile); + checkNotNull(tenantProfile, "Tenant profile with id [" + tenantProfileId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, operation); return tenantProfile; } catch (Exception e) { @@ -429,7 +437,7 @@ public abstract class BaseController { try { validateId(customerId, "Incorrect customerId " + customerId); Customer customer = customerService.findCustomerById(getTenantId(), customerId); - checkNotNull(customer); + checkNotNull(customer, "Customer with id [" + customerId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.CUSTOMER, operation, customerId, customer); return customer; } catch (Exception e) { @@ -441,7 +449,7 @@ public abstract class BaseController { try { validateId(userId, "Incorrect userId " + userId); User user = userService.findUserById(getCurrentUser().getTenantId(), userId); - checkNotNull(user); + checkNotNull(user, "User with id [" + userId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.USER, operation, userId, user); return user; } catch (Exception e) { @@ -460,7 +468,9 @@ public abstract class BaseController { protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException { try { - checkNotNull(entityId); + if (entityId == null) { + throw new ThingsboardException("Parameter entityId can't be empty!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } validateId(entityId.getId(), "Incorrect entityId " + entityId); switch (entityId.getEntityType()) { case ALARM: @@ -526,7 +536,7 @@ public abstract class BaseController { try { validateId(deviceId, "Incorrect deviceId " + deviceId); Device device = deviceService.findDeviceById(getCurrentUser().getTenantId(), deviceId); - checkNotNull(device); + checkNotNull(device, "Device with id [" + deviceId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device); return device; } catch (Exception e) { @@ -538,7 +548,7 @@ public abstract class BaseController { try { validateId(deviceId, "Incorrect deviceId " + deviceId); DeviceInfo device = deviceService.findDeviceInfoById(getCurrentUser().getTenantId(), deviceId); - checkNotNull(device); + checkNotNull(device, "Device with id [" + deviceId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device); return device; } catch (Exception e) { @@ -550,7 +560,7 @@ public abstract class BaseController { try { validateId(deviceProfileId, "Incorrect deviceProfileId " + deviceProfileId); DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(getCurrentUser().getTenantId(), deviceProfileId); - checkNotNull(deviceProfile); + checkNotNull(deviceProfile, "Device profile with id [" + deviceProfileId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE_PROFILE, operation, deviceProfileId, deviceProfile); return deviceProfile; } catch (Exception e) { @@ -562,7 +572,7 @@ public abstract class BaseController { try { validateId(entityViewId, "Incorrect entityViewId " + entityViewId); EntityView entityView = entityViewService.findEntityViewById(getCurrentUser().getTenantId(), entityViewId); - checkNotNull(entityView); + checkNotNull(entityView, "Entity view with id [" + entityViewId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, entityViewId, entityView); return entityView; } catch (Exception e) { @@ -574,7 +584,7 @@ public abstract class BaseController { try { validateId(entityViewId, "Incorrect entityViewId " + entityViewId); EntityViewInfo entityView = entityViewService.findEntityViewInfoById(getCurrentUser().getTenantId(), entityViewId); - checkNotNull(entityView); + checkNotNull(entityView, "Entity view with id [" + entityViewId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, entityViewId, entityView); return entityView; } catch (Exception e) { @@ -586,7 +596,7 @@ public abstract class BaseController { try { validateId(assetId, "Incorrect assetId " + assetId); Asset asset = assetService.findAssetById(getCurrentUser().getTenantId(), assetId); - checkNotNull(asset); + checkNotNull(asset, "Asset with id [" + assetId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, assetId, asset); return asset; } catch (Exception e) { @@ -598,7 +608,7 @@ public abstract class BaseController { try { validateId(assetId, "Incorrect assetId " + assetId); AssetInfo asset = assetService.findAssetInfoById(getCurrentUser().getTenantId(), assetId); - checkNotNull(asset); + checkNotNull(asset, "Asset with id [" + assetId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, assetId, asset); return asset; } catch (Exception e) { @@ -610,7 +620,7 @@ public abstract class BaseController { try { validateId(alarmId, "Incorrect alarmId " + alarmId); Alarm alarm = alarmService.findAlarmByIdAsync(getCurrentUser().getTenantId(), alarmId).get(); - checkNotNull(alarm); + checkNotNull(alarm, "Alarm with id [" + alarmId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarmId, alarm); return alarm; } catch (Exception e) { @@ -622,7 +632,7 @@ public abstract class BaseController { try { validateId(alarmId, "Incorrect alarmId " + alarmId); AlarmInfo alarmInfo = alarmService.findAlarmInfoByIdAsync(getCurrentUser().getTenantId(), alarmId).get(); - checkNotNull(alarmInfo); + checkNotNull(alarmInfo, "Alarm with id [" + alarmId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarmId, alarmInfo); return alarmInfo; } catch (Exception e) { @@ -634,7 +644,7 @@ public abstract class BaseController { try { validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId); WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(getCurrentUser().getTenantId(), widgetsBundleId); - checkNotNull(widgetsBundle); + checkNotNull(widgetsBundle, "Widgets bundle with id [" + widgetsBundleId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.WIDGETS_BUNDLE, operation, widgetsBundleId, widgetsBundle); return widgetsBundle; } catch (Exception e) { @@ -646,7 +656,7 @@ public abstract class BaseController { try { validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId); WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(getCurrentUser().getTenantId(), widgetTypeId); - checkNotNull(widgetTypeDetails); + checkNotNull(widgetTypeDetails, "Widget type with id [" + widgetTypeId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, operation, widgetTypeId, widgetTypeDetails); return widgetTypeDetails; } catch (Exception e) { @@ -658,7 +668,7 @@ public abstract class BaseController { try { validateId(dashboardId, "Incorrect dashboardId " + dashboardId); Dashboard dashboard = dashboardService.findDashboardById(getCurrentUser().getTenantId(), dashboardId); - checkNotNull(dashboard); + checkNotNull(dashboard, "Dashboard with id [" + dashboardId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, dashboardId, dashboard); return dashboard; } catch (Exception e) { @@ -670,7 +680,7 @@ public abstract class BaseController { try { validateId(edgeId, "Incorrect edgeId " + edgeId); Edge edge = edgeService.findEdgeById(getTenantId(), edgeId); - checkNotNull(edge); + checkNotNull(edge, "Edge with id [" + edgeId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edgeId, edge); return edge; } catch (Exception e) { @@ -682,7 +692,7 @@ public abstract class BaseController { try { validateId(edgeId, "Incorrect edgeId " + edgeId); EdgeInfo edge = edgeService.findEdgeInfoById(getCurrentUser().getTenantId(), edgeId); - checkNotNull(edge); + checkNotNull(edge, "Edge with id [" + edgeId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edgeId, edge); return edge; } catch (Exception e) { @@ -694,7 +704,7 @@ public abstract class BaseController { try { validateId(dashboardId, "Incorrect dashboardId " + dashboardId); DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(getCurrentUser().getTenantId(), dashboardId); - checkNotNull(dashboardInfo); + checkNotNull(dashboardInfo, "Dashboard with id [" + dashboardId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, dashboardId, dashboardInfo); return dashboardInfo; } catch (Exception e) { @@ -732,7 +742,7 @@ public abstract class BaseController { protected RuleChain checkRuleChain(RuleChainId ruleChainId, Operation operation) throws ThingsboardException { validateId(ruleChainId, "Incorrect ruleChainId " + ruleChainId); RuleChain ruleChain = ruleChainService.findRuleChainById(getCurrentUser().getTenantId(), ruleChainId); - checkNotNull(ruleChain); + checkNotNull(ruleChain, "Rule chain with id [" + ruleChainId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.RULE_CHAIN, operation, ruleChainId, ruleChain); return ruleChain; } @@ -740,7 +750,7 @@ public abstract class BaseController { protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation) throws ThingsboardException { validateId(ruleNodeId, "Incorrect ruleNodeId " + ruleNodeId); RuleNode ruleNode = ruleChainService.findRuleNodeById(getTenantId(), ruleNodeId); - checkNotNull(ruleNode); + checkNotNull(ruleNode, "Rule node with id [" + ruleNodeId + "] is not found"); checkRuleChain(ruleNode.getRuleChainId(), operation); return ruleNode; } @@ -749,7 +759,7 @@ public abstract class BaseController { try { validateId(resourceId, "Incorrect resourceId " + resourceId); TbResource resource = resourceService.findResourceById(getCurrentUser().getTenantId(), resourceId); - checkNotNull(resource); + checkNotNull(resource, "Resource with id [" + resourceId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resource); return resource; } catch (Exception e) { @@ -761,7 +771,7 @@ public abstract class BaseController { try { validateId(resourceId, "Incorrect resourceId " + resourceId); TbResourceInfo resourceInfo = resourceService.findResourceInfoById(getCurrentUser().getTenantId(), resourceId); - checkNotNull(resourceInfo); + checkNotNull(resourceInfo, "Resource with id [" + resourceId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resourceInfo); return resourceInfo; } catch (Exception e) { @@ -773,7 +783,7 @@ public abstract class BaseController { try { validateId(otaPackageId, "Incorrect otaPackageId " + otaPackageId); OtaPackage otaPackage = otaPackageService.findOtaPackageById(getCurrentUser().getTenantId(), otaPackageId); - checkNotNull(otaPackage); + checkNotNull(otaPackage, "OTA package with id [" + otaPackageId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.OTA_PACKAGE, operation, otaPackageId, otaPackage); return otaPackage; } catch (Exception e) { @@ -785,7 +795,7 @@ public abstract class BaseController { try { validateId(otaPackageId, "Incorrect otaPackageId " + otaPackageId); OtaPackageInfo otaPackageIn = otaPackageService.findOtaPackageInfoById(getCurrentUser().getTenantId(), otaPackageId); - checkNotNull(otaPackageIn); + checkNotNull(otaPackageIn, "OTA package with id [" + otaPackageId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.OTA_PACKAGE, operation, otaPackageId, otaPackageIn); return otaPackageIn; } catch (Exception e) { @@ -797,7 +807,7 @@ public abstract class BaseController { try { validateId(rpcId, "Incorrect rpcId " + rpcId); Rpc rpc = rpcService.findById(getCurrentUser().getTenantId(), rpcId); - checkNotNull(rpc); + checkNotNull(rpc, "RPC with id [" + rpcId + "] is not found"); accessControlService.checkPermission(getCurrentUser(), Resource.RPC, operation, rpcId, rpc); return rpc; } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index 12a5c74588..7611d2da25 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -240,7 +240,7 @@ public class CustomerController extends BaseController { @RequestParam String customerTitle) throws ThingsboardException { try { TenantId tenantId = getCurrentUser().getTenantId(); - return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle)); + return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle), "Customer with title [" + customerTitle + "] is not found"); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 4bc23f3fb0..c10234042a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -19,6 +19,9 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.Example; +import io.swagger.annotations.ExampleProperty; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -106,6 +109,7 @@ public class DashboardController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET) @ResponseBody + @ApiResponse(code = 200, message = "OK", examples = @Example(value = @ExampleProperty(value = "1636023857137", mediaType = "application/json"))) public long getServerTime() throws ThingsboardException { return System.currentTimeMillis(); } @@ -118,6 +122,7 @@ public class DashboardController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/dashboard/maxDatapointsLimit", method = RequestMethod.GET) @ResponseBody + @ApiResponse(code = 200, message = "OK", examples = @Example(value = @ExampleProperty(value = "5000", mediaType = "application/json"))) public long getMaxDatapointsLimit() throws ThingsboardException { return maxDatapointsLimit; } diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java index 906e87d608..36657e9a91 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java @@ -17,9 +17,13 @@ package org.thingsboard.server.exception; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; @@ -30,7 +34,9 @@ import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import org.springframework.web.util.WebUtils; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.msg.tools.TbRateLimitsException; @@ -42,11 +48,49 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; @Slf4j @RestControllerAdvice public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHandler implements AccessDeniedHandler { + private static final Map statusToErrorCodeMap = new HashMap<>(); + static { + statusToErrorCodeMap.put(HttpStatus.BAD_REQUEST, ThingsboardErrorCode.BAD_REQUEST_PARAMS); + statusToErrorCodeMap.put(HttpStatus.UNAUTHORIZED, ThingsboardErrorCode.AUTHENTICATION); + statusToErrorCodeMap.put(HttpStatus.FORBIDDEN, ThingsboardErrorCode.PERMISSION_DENIED); + statusToErrorCodeMap.put(HttpStatus.NOT_FOUND, ThingsboardErrorCode.ITEM_NOT_FOUND); + statusToErrorCodeMap.put(HttpStatus.METHOD_NOT_ALLOWED, ThingsboardErrorCode.BAD_REQUEST_PARAMS); + statusToErrorCodeMap.put(HttpStatus.NOT_ACCEPTABLE, ThingsboardErrorCode.BAD_REQUEST_PARAMS); + statusToErrorCodeMap.put(HttpStatus.UNSUPPORTED_MEDIA_TYPE, ThingsboardErrorCode.BAD_REQUEST_PARAMS); + statusToErrorCodeMap.put(HttpStatus.TOO_MANY_REQUESTS, ThingsboardErrorCode.TOO_MANY_REQUESTS); + statusToErrorCodeMap.put(HttpStatus.INTERNAL_SERVER_ERROR, ThingsboardErrorCode.GENERAL); + statusToErrorCodeMap.put(HttpStatus.SERVICE_UNAVAILABLE, ThingsboardErrorCode.GENERAL); + } + private static final Map errorCodeToStatusMap = new HashMap<>(); + static { + errorCodeToStatusMap.put(ThingsboardErrorCode.GENERAL, HttpStatus.INTERNAL_SERVER_ERROR); + errorCodeToStatusMap.put(ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED); + errorCodeToStatusMap.put(ThingsboardErrorCode.JWT_TOKEN_EXPIRED, HttpStatus.UNAUTHORIZED); + errorCodeToStatusMap.put(ThingsboardErrorCode.CREDENTIALS_EXPIRED, HttpStatus.UNAUTHORIZED); + errorCodeToStatusMap.put(ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN); + errorCodeToStatusMap.put(ThingsboardErrorCode.INVALID_ARGUMENTS, HttpStatus.BAD_REQUEST); + errorCodeToStatusMap.put(ThingsboardErrorCode.BAD_REQUEST_PARAMS, HttpStatus.BAD_REQUEST); + errorCodeToStatusMap.put(ThingsboardErrorCode.ITEM_NOT_FOUND, HttpStatus.NOT_FOUND); + errorCodeToStatusMap.put(ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS); + errorCodeToStatusMap.put(ThingsboardErrorCode.TOO_MANY_UPDATES, HttpStatus.TOO_MANY_REQUESTS); + errorCodeToStatusMap.put(ThingsboardErrorCode.SUBSCRIPTION_VIOLATION, HttpStatus.FORBIDDEN); + } + + private static ThingsboardErrorCode statusToErrorCode(HttpStatus status) { + return statusToErrorCodeMap.getOrDefault(status, ThingsboardErrorCode.GENERAL); + } + + private static HttpStatus errorCodeToStatus(ThingsboardErrorCode errorCode) { + return errorCodeToStatusMap.getOrDefault(errorCode, HttpStatus.INTERNAL_SERVER_ERROR); + } + @Autowired private ObjectMapper mapper; @@ -95,36 +139,22 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand } } + @NotNull + @Override + protected ResponseEntity handleExceptionInternal( + @NotNull Exception ex, @Nullable Object body, + @NotNull HttpHeaders headers, @NotNull HttpStatus status, + @NotNull WebRequest request) { + if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) { + request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST); + } + ThingsboardErrorCode errorCode = statusToErrorCode(status); + return new ResponseEntity<>(ThingsboardErrorResponse.of(ex.getMessage(), errorCode, status), headers, status); + } private void handleThingsboardException(ThingsboardException thingsboardException, HttpServletResponse response) throws IOException { - ThingsboardErrorCode errorCode = thingsboardException.getErrorCode(); - HttpStatus status; - - switch (errorCode) { - case AUTHENTICATION: - status = HttpStatus.UNAUTHORIZED; - break; - case PERMISSION_DENIED: - status = HttpStatus.FORBIDDEN; - break; - case INVALID_ARGUMENTS: - status = HttpStatus.BAD_REQUEST; - break; - case ITEM_NOT_FOUND: - status = HttpStatus.NOT_FOUND; - break; - case BAD_REQUEST_PARAMS: - status = HttpStatus.BAD_REQUEST; - break; - case GENERAL: - status = HttpStatus.INTERNAL_SERVER_ERROR; - break; - default: - status = HttpStatus.INTERNAL_SERVER_ERROR; - break; - } - + HttpStatus status = errorCodeToStatus(errorCode); response.setStatus(status.value()); mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(thingsboardException.getMessage(), errorCode, status)); } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index a33beaa535..ebf5501f4a 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -89,6 +89,11 @@ server: # Default value of the server side RPC timeout. default_timeout: "${DEFAULT_SERVER_SIDE_RPC_TIMEOUT:10000}" +# Application info +app: + # Application version + version: "@project.version@" + # Zookeeper connection parameters. Used for service discovery. zk: # Enable/disable zookeeper discovery service. @@ -859,7 +864,7 @@ swagger: license: title: "${SWAGGER_LICENSE_TITLE:Apache License Version 2.0}" url: "${SWAGGER_LICENSE_URL:https://github.com/thingsboard/thingsboard/blob/master/LICENSE}" - version: "${SWAGGER_VERSION:2.0}" + version: "${SWAGGER_VERSION:}" queue: type: "${TB_QUEUE_TYPE:in-memory}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java index 61328dd352..5467db00e3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java @@ -58,7 +58,7 @@ public class AdminSettings extends BaseData { return super.getCreatedTime(); } - @ApiModelProperty(position = 3, value = "The Administration Settings key, (e.g. 'general' or 'mail')") + @ApiModelProperty(position = 3, value = "The Administration Settings key, (e.g. 'general' or 'mail')", example = "mail") public String getKey() { return key; } diff --git a/pom.xml b/pom.xml index 1c73f6b919..e5ce0161ac 100755 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ 4.8.0 2.19.1 3.0.2 - 3.0.3 + 3.0.4 1.6.3 0.7 1.15.0 diff --git a/transport/lwm2m/src/main/data/lwm2mserver.jks b/transport/lwm2m/src/main/data/lwm2mserver.jks index 9f6748f8fdab7179b895eccd71421fe1565d27db..5fab824aa1b19928fe711701cd27857472a9e739 100644 GIT binary patch delta 3653 zcmV-L4!ZI29*G_zFoF*S0s#Xsf)2h02`Yw2hW8Bt2LYgh4zC1)4y!PN4yTbKM1Ly* zom9BjJH$VcW(h0D2xIlY6r2JB0K-rOftaAyg&4(nOgQGgqZXKQNpgf$5vgZ}((Ysq z4>NDXm)2g@Mz`$C_E~pf2sbe$VNxNWg7CwD5uTlTd647vCxxS`5^~+i%3oo$<=Ut7 z96^zpSju@r$84gNVErKYNtV0q%r!bu0bINIX>{=o{Yo;qIe}jww@|a@ui(dgepJ8kd7lOaQD49BSZNR~ob$&O zk7x0cF9b%YM6(;R& z>c*G%1)}{X$%f_0t8V_&LNQU|0xkI3^#2v9Vh5%nhr zdsYmeWIv&B_#`cG{+tpJXY%zh<=zWf`~HA8b=FeEgQU!~(4G ztKp3!X7^z8TDs_-``@hRMC~tFi0__dxX*0}y=Ku+K_v3MQFss)6Mo3)N80o-GGc*W zqtL?nMDyA^8LxWo6s#(8BiGE*b(LJ80%S2I&;7tsS(Iud<2!Pq_7 z>J=D1|4`9nwAA=Bq*ee8T-oXYHqazGaBBxrAXf*xG306XETw{w1^@SbxoZrvB@7;< zIy#$$kn-oXcBOFb)gkUIjST)S6{Ak92W>iRfVl+>usEb%U`2m36mhpc(00T)sv9GL zZ$jfE=kcjZc;`J2HCB6CQ+Eo7vSpHPUfWuethbwDt_0oBbK8itz))(CMpr(R5B)?P zr~DX{n}1`D_WP?4W03usm03LnEe=atcZtA`B*4ji@MFI(hQ39`@cD~Jm?|Q>hp}MW zBP@1lTH|X@8(n|F3|tdOGU;dyMo*r%EEoj4(AO?W6L_WzK@B8a=dAk*lyd}Y<7RD8 zDR_+ERe&|!dTY>%hp9MP7c&=^FE3G%ga}k|^ApCxZyug=Q~wXW5j~F7WcH?x(18$d$?BpD-!$GC$eMt*93*}cRz@aC95vE zbo>Sjw~sSB?w+EcFhyjs5{!UFV^-YTX%vVAhx>n^P-^UJXp-RJAa8XB*qyRCj4cb- zRtI9BFx%wgz?Us z>oeetM}}cMV%1rd6J2x=wbRcLN|8R~st2r>ihqh38kECo?4fkJ)xNFJY}~=Z($G^E zA4-3tRMmld%nq7rkiC7%j-v#>2eMo|rUrNcT5$ea>7}Xj%0nMK0{lqoAh{EZWMFU2 z?!>~Mgb!SzeS4;xt}k}YQPqtxR@Yn-@Hk5Wx~hyDCk?gu)|OLkjL1s{>wRy@#2VmJ znoX1$=4b9mXv3K@I|f|Vd$T-lnF@i5Gpv7p{faHOI1{2$$;VcAM3>05@M7iAS`rs$ z*>pBhPp@>$(p>6^lmSApfZ%ati8_sF%z5n?;Gd^})wsAe;;qNqGJ5EEVj_h^rjoiWJAij^KT^KiemaQ*LCt~Vc3%5HuZn3TM|`;hAj3=a2h^{>eVrKIz$R}Fvl zJmCbxlRb|8U1EGj>#%#?-0qpbg5%1jjtN{&7vZS1JWUwzOU*9CNd2I*Bh-IfF^e%EmB7aaH-T0k*XL=`2^+C)>&jSZDe07V z|I4%HQH%Z1cDBB=vQ{6O*i<~L$P2-tsvZF+z6@(L<9ULG}>YN;%*B} zo&7)}<#)+(z{3{ma15xSj5$<%gE8F$A`EY_1d*@2ih?hm5)@&g{7Mb)ksyDSG8&tf zy48HrJ=34^yU*BnZ-6)`d`kR{RlA-@FbKSdbT#z*a`oMRyDQ}(Y!Qz!7PXIi?fNU+8JZJq?OJ9`gFo!Nn# zJCbbf)Pv82Lg$-wQ^T0FuBCqjsZnQZ_=7L}nJGtg^kAfH_h>wCtmB=X(v5|JM&@4J z*!#O;?Iq-XrN~m6R?p#9m)=}89sSH4jHKB;+L4A}Oi}=aCpZbb)W4d$ycoK`a@(&nXPD_7-8se;v2?#i@ z5|D*$W`hvY#F2L^dgS||;U-%m<8vK$+$eenj(YkZGz`+!`utjH=I*+sSFly$5KZK- zFSX4GPUe4~V!<7M_@B_sv@R4UoRo~)Ch$#3{30wRJ}2$##*6+N0F0Nv8NK-)mpX% z@4ostl_4ISiSl`rqt%-|_XE@aqA8<&YKiWy4$Z;oCpZ5nke+|c+~anTHd3P{mchxm ziE75=L4LzN-xtubZ8rc8A5+5}2#^ait_(WiB%^Z9ZWf=I=!O~HFS36eL^p6)v7Y5I zHz=sWEy^;s*M!^Fc)G|#SVGq}IHPJQOMBumSC^kVQ=~>gBr+a+Rq^?u{AGuFAQC@k zga)8!>>xqoC)nH6A<3~Y3s`@$#AV!Yr@k@`^o)oX>E1sT~Ag1wYDw5<6 zKV?q$Z-+AvG4p83!1rXSjAb!yr3$w4j0RBTz~66KXsds>x#XDMYi3=pj>usTFx|%e z2eODYW|KtQ`#XAByPJWfo?Pl>Y`FFf85H$>vVpi1+tlTD%@T}rSh`0Qj&hHNA4Y?| zOPd^d=-Zj_qh z)daLS3Q_pFP7FV!9CMWn*||txn|zMf8}{Jbz&sV9Q4sV%qUMzf@94TQ9jiR|;Qyr6 zb5g1e=SHGl^<8Y;LJ>?l!$^!hP=4 zWm$j!_x{)#<)ro~78OK;d#S{RBNWNJ;i?W`h9Q=9m(#`#uhmanl9}D7KVW!QHs`I- zt_jMk?j3^zaB9wh8rlvdeMQfNAe?3OXp#e_MLJ>nJ;)IVeyYZ8MSt`=*@GH-9sr@< zs-P+(o5bz0Fg`FLFbM_)D-Ht!8U+9Z6xYT>#LaQo(*VtnzN_qMP4M!Fhy)b<1nu-# X_d}DEK0Izji}dfgHE9+C0|ADhaZ(kz delta 3758 zcmV;f4pH%m9`PO`FoF+l0s#Xsf)6GJ2`Yw2hW8Bt2LYgh4;KW24-+tg4-b(dM1S-i z{srVqTGKEDaK2q&C*civrQ!ku0K-rOftY_W?dJLp*IR#Gc*!!xkpxE?wSF%W|6}_C zVqQ(g1?5uTlGag0&^c3`lU=^W>izj-T7{iDN&27>DOY+qHvUmtH2n3den$f;82fv2 zmBu!DS_FEdwT7F%f~R0@YJ42Rk2T5+bK`W-6?=o4(zV>6+8)fW5y+KjISE|QdhbFS ze3x#V^%TSREb9F`ENS$a>+MLW9--%x8UZ&CF*7nUHaIjmG&nLaf&n3sK_!1B5v#8o zUP=N1_%{{P>a~$lh=*DN0|3KN1c8{f3i>!()nXP2mOE4kkxSw!Hox+qA(3G2T$Sb* z*?Hl6f+<7&D3!y&QLoC~J2mf1y$-(Ls@OYsgBij&LNQU)RNo3>bAG$3Rz_n)NE)9t=eP2Ke*b)I2qPlt>Tk8!{cz5t1oikCNS1 zCcHPY|G_#|MCQm~`l1{{Zx@20KQjKfbxrTjr&KpZc4U$#j1pA5yKoOjLyA zAGBtRSisO-F9=!rwy#ko&xnl-^7-qYb87KZ08QTTwwa1vZ=ran1-van5_znwqoC6M zr_C=XqZT_9YnId8=>2QPgIhw0Z_PpLqxzzwDJKeZ&V1+De>Yx@AC_nJo}lUFEuBgd z3kRt=5Aj2$cm<%_CIq0Z> z@~)y&cPOg!<~6^O5N;Xm8w2PQxLX=oC1T9Fh`EyU<1O`?ar}Ql1j@^4g1bno6P@tj zC07JVoS2;6Z2b+$a2G7Eevy=zj$U zJlkqdCriZmaQG9|!W(0b%weA%o$s+tLF#L|y&8udAAb!zZw<#J!r_#_pEN-J0dy!r z++6QEOW$*1fsB7N3YQpmS#Syy7N}6qV!5O40tCr!t^JA)rDSOgOai|;p6zJwj_q( z06;bY`T19Pyl*YNYd33n3o34U!PwIQV0-^!M>FqQK<6@X^Iam(6aXxv2QP+L%qMZF zzpH)egz$gNNw%pMeekD5#0E_YOg!>6^`PucYmlo^$snKT zFJC%2E4(7)0f7i+VLc>_rQ6Ft(WUq}KxyLb+H8LttD*Se=H^xfV6VpEYq-u7aF83W zarF6tIoO5FKce|qn6w8a*wrN;)R11|pQ~l@@DsWwJ=Y7PVF$(mO-9cei-Gb{geXMt zKa*N3RZh=+!>UZKaLN(;#tHEf4#dC&@2&`W(Srf*bzv*_n^)hj&_b01>&;J`31l z(1}w7mP1uT7WxvERM16tE#*6U+yFF7Upa5L*B+B-NDZl_P~M}tDe&okQhg$V;ktiD zV^NUY^@4!~l31+g=jB#3*!F2SgwB5|)$T&b{h4w)Yavalvk~mbMmiIaRvx%vS!uuk zL1UvtC}lR+*`TkDHmt-Dfi$6@A$E&oV}!>S2b^jqfzmh`t=2gS`Ke%xZ}|1F_Jp%w zrIKuDOSf(tpg8Qa7p|jm?YX||zTxo~NTRCBSyD4t!t`)fWiD70COw=UPp*Hev!tQn z^44DgA}8B?Oqf$ECe>t;R=}%78o!yc$Jh_pc1fd~zx_W!mmG0?QunF9#es|?Zm^?Z zlLCct^SEnEMz_Xuyk0d2c~c3vEy9!~s>fZ-L5Kw2n9JS3_|>QiHg_pbj@sDp$7p`g z2w0I=0~MDJ9|KJhU;|-5w+Dax9-52ik*iW);Nr|+y@AylI_9;$tzeFS_}=|rg%9h} zogN`kY)D%rURD$Uf8oZg->{#4{k;MJM~X;)f`$gUw`V0t)>5nb--SpGUjMbq4Wbzm zy{oJx6~I{-OW@_ne8&IlLm**XS-V|rFnBBGSEeI2T;nCdV=@7ymfnATIB4XLeZD`` z(Tu~>sovCMYKTS>6gqe1!M?i-G6s-$2MuZLbh9NlzvSRW7jf6C;x2wy%}N*eC@AHB zPUU=Gj9#JOXR4dmpGsE?48meK^)Lgn^-yrAiEDaD*LuS+2~^#oQ)rLOIJ^&56W)FZ=A}u4m8##UC&C-G*nMTgm(38T&SR z?1(FWOY!Ypa2%}h=t5t)INw@L;qJ!68jqPhx)L z-E1PfXH?2kRYVinz&+Rp#VL z^1Lmcc2$0}=)9z)c3^`+tN1GaG{r#ZL&iNXZ{3Q%cJt0lKf1b|aCAd|tlqyTN+FV~8O%+Y4J0IDXKP)S znZRdG8euiXnVsX*2a~-g9QZYD=CkiH5?J>2ldTr0U_z5I=?EsbWlGkM$Ab-!Hjf#R zDJ-FbsuvSjx@0s#MgBmzZ_J*~JVz6`$OvLmQayj>)fIbeN+CgEMQ${Z5f)cOK@l{AyD=YZZsu>XwMF}_E|Lr$}-Vlv$aBN8+U zIXHjxcXZ+c#=okogeWoalI4N6r^i+CP&}`d2|5mmgB2AjiANzX1dEsS!CYj!p>C0< z20euq-Mob|^0$+Mgtk09EG)Y>qW+FtJ0(>!uNe>#E(e|PNO8qAxigumEjsQUy#4c^ z7_6iUE{bIsE3H}m>WUXAD^-LAOJ2pyGj4w_lfaz|QqF%Dx+T$)CTmyo(#6N3(RY1{ z0Wt(;QX*T8c>P!Npaas2QHN48Y$?A0G;kW$7?cW;jH3^rX6y~4nf}|L^lQFk_%(F9 zLhK}#H+IPKl5cmQGRu|HSt5(!+*Q)?4P^chb+LpjDpQb|%dkUO!p|<~&-!`bvUq=_ zVXoO)iogr>B&(<$=h1?Abc@rfUD}-3T#DH2jOu zXAl25fHe(E3pcvz=t$e|htX7_%QAn^Qtl&Ln>|s^4)5A@t*?G9w!0Jf5!&V=Q-}UN z Date: Thu, 4 Nov 2021 15:59:13 +0200 Subject: [PATCH 208/303] Update rule nodes UI --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 17f2ee6af1..cea69d4d4e 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 @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
        "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
        tb.rulenode.notify-device-hint
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
        \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
        \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
        \n
        \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
        \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
        tb.rulenode.create-entity-if-not-exists-hint
        \n
        \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
        tb.rulenode.remove-current-relations-hint
        \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
        tb.rulenode.change-originator-to-related-entity-hint
        \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
        \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-period-in-seconds-patterns-hint
        \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
        \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.delete-relation-hint
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
        \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
        \n \n \n \n
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
        \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
        \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
        \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
        \n
        \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
        \n
        \n
        \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
        \n
        \n \n
        \n \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-type
        \n \n \n
        device.device-types
        \n \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-filters
        \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-message-types-found\n
        \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
        \n
        \n
        \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
        \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
        {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
        \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
        \n
        \n
        \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
        \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
        \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
        \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
        tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
        \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
        \n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
        \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
        \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n
        \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
        \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
        \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
        \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
        \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
        \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
        \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
        \n
        \n
        \n
        \n
        \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
        \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
        \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
        \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
        tb.rulenode.check-all-keys-hint
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
        \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.check-relation-hint
        \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
        \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
        \n \n \n \n
        \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
        \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-alarm-status-matching\n
        \n
        \n
        \n
        \n
        \n \n
        \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
        \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-entity-details-matching\n
        \n
        \n
        \n
        \n
        \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
        tb.rulenode.add-to-metadata-hint
        \n
        \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
        \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
        \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
        \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.aggregationTypes=a.AggregationType,n.aggregations=Object.keys(a.AggregationType),n.aggregationTypesTranslations=a.aggregationTranslations,n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[i.Validators.required]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
        \n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
        \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-interval-patterns-hint
        \n
        \n
        \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
        \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
        \n
        \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
        \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
        \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
        \n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
        \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
        "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
        tb.rulenode.notify-device-hint
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
        \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
        \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
        \n
        \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
        \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
        tb.rulenode.create-entity-if-not-exists-hint
        \n
        \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
        tb.rulenode.remove-current-relations-hint
        \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
        tb.rulenode.change-originator-to-related-entity-hint
        \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
        \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-period-in-seconds-patterns-hint
        \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
        \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.delete-relation-hint
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
        \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
        \n \n \n \n
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
        \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
        \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
        \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
        \n
        \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
        \n
        \n
        \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
        \n
        \n \n
        \n \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-type
        \n \n \n
        device.device-types
        \n \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-filters
        \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-message-types-found\n
        \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
        \n
        \n
        \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
        \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
        {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
        \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
        \n
        \n
        \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
        \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
        \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
        \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
        tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
        \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
        \n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
        \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
        \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n
        \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
        \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
        \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
        \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
        \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
        \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
        \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
        \n
        \n
        \n
        \n
        \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
        \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
        \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
        \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
        tb.rulenode.check-all-keys-hint
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
        \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.check-relation-hint
        \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
        \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
        \n \n \n \n
        \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
        \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-alarm-status-matching\n
        \n
        \n
        \n
        \n
        \n \n
        \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
        \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-entity-details-matching\n
        \n
        \n
        \n
        \n
        \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
        tb.rulenode.add-to-metadata-hint
        \n
        \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
        \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
        \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
        \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.aggregationTypes=a.AggregationType,n.aggregations=Object.keys(a.AggregationType),n.aggregationTypesTranslations=a.aggregationTranslations,n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[i.Validators.required]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
        \n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
        \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-interval-patterns-hint
        \n
        \n
        \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
        \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
        \n
        \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
        \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
        \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
        \n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
        \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 17f9eebe23e8620e3e9b33b1c7c88a3c987b8d1e Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Thu, 4 Nov 2021 12:09:07 +0200 Subject: [PATCH 209/303] Set serialVersionUIDs for cached entities --- .../java/org/thingsboard/server/dao/device/claim/ClaimData.java | 2 ++ .../java/org/thingsboard/server/common/data/TenantProfile.java | 2 ++ .../thingsboard/server/common/data/kv/BaseAttributeKvEntry.java | 2 ++ .../server/common/data/security/model/SecuritySettings.java | 2 ++ 4 files changed, 8 insertions(+) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/claim/ClaimData.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/claim/ClaimData.java index 8e74af907b..9fa6c4d55f 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/claim/ClaimData.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/claim/ClaimData.java @@ -24,6 +24,8 @@ import java.io.Serializable; @Data public class ClaimData implements Serializable { + private static final long serialVersionUID = -3922621193389915930L; + private final String secretKey; private final long expirationTime; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java index 2d1a575f1c..7ca85eecc2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java @@ -39,6 +39,8 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn @Slf4j public class TenantProfile extends SearchTextBased implements HasName { + private static final long serialVersionUID = 3021989561267192281L; + @NoXss @ApiModelProperty(position = 3, value = "Name of the tenant profile", example = "High Priority Tenants") private String name; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java index d87c260898..d54ef35966 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java @@ -24,6 +24,8 @@ import java.util.Optional; */ public class BaseAttributeKvEntry implements AttributeKvEntry { + private static final long serialVersionUID = -6460767583563159407L; + private final long lastUpdateTs; private final KvEntry kv; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/SecuritySettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/SecuritySettings.java index 5c1972d1e1..7298154162 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/SecuritySettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/SecuritySettings.java @@ -25,6 +25,8 @@ import java.io.Serializable; @Data public class SecuritySettings implements Serializable { + private static final long serialVersionUID = -1307613974597312465L; + @ApiModelProperty(position = 1, value = "The user password policy object." ) private UserPasswordPolicy passwordPolicy; @ApiModelProperty(position = 2, value = "Maximum number of failed login attempts allowed before user account is locked." ) From 52d626882bc7fbfd3d9b85f2053163bbf53d625b Mon Sep 17 00:00:00 2001 From: Swoq Date: Wed, 6 Oct 2021 13:33:42 +0300 Subject: [PATCH 210/303] Fix exception after changing polygon on widget --- .../thingsboard/rule/engine/geo/GeoUtil.java | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java index b5612dfc6a..a67693749e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java @@ -45,24 +45,42 @@ public class GeoUtil { } public static synchronized boolean contains(String polygon, Coordinates coordinates) { - ShapeFactory.PolygonBuilder polygonBuilder = jtsCtx.getShapeFactory().polygon(); JsonArray polygonArray = new JsonParser().parse(polygon).getAsJsonArray(); - boolean first = true; + + JsonArray arrayWithCoords = polygonArray; + JsonArray innerArray = polygonArray.get(0).getAsJsonArray(); + if (!containsPrimitives(innerArray)) { + arrayWithCoords = innerArray; + } + + Shape shape = buildPolygonFromJsonCoords(arrayWithCoords); + Point point = jtsCtx.getShapeFactory().pointXY(coordinates.getLongitude(), coordinates.getLatitude()); + return shape.relate(point).equals(SpatialRelation.CONTAINS); + } + + private static Shape buildPolygonFromJsonCoords(JsonArray coordinates) { + ShapeFactory.PolygonBuilder polygonBuilder = jtsCtx.getShapeFactory().polygon(); + boolean isFirst = true; double firstLat = 0.0; double firstLng = 0.0; - for (JsonElement jsonElement : polygonArray) { - double lat = jsonElement.getAsJsonArray().get(0).getAsDouble(); - double lng = jsonElement.getAsJsonArray().get(1).getAsDouble(); - if (first) { + for (JsonElement element : coordinates) { + double lat = element.getAsJsonArray().get(0).getAsDouble(); + double lng = element.getAsJsonArray().get(1).getAsDouble(); + if (isFirst) { firstLat = lat; firstLng = lng; - first = false; + isFirst = false; } - polygonBuilder.pointXY(jtsCtx.getShapeFactory().normX(lng), jtsCtx.getShapeFactory().normY(lat)); + polygonBuilder.pointXY(jtsCtx.getShapeFactory().normX(lng), jtsCtx.getShapeFactory().normX(lat)); } - polygonBuilder.pointXY(jtsCtx.getShapeFactory().normX(firstLng), jtsCtx.getShapeFactory().normY(firstLat)); - Shape shape = polygonBuilder.buildOrRect(); - Point point = jtsCtx.getShapeFactory().pointXY(coordinates.getLongitude(), coordinates.getLatitude()); - return shape.relate(point).equals(SpatialRelation.CONTAINS); + polygonBuilder.pointXY(jtsCtx.getShapeFactory().normX(firstLng), jtsCtx.getShapeFactory().normX(firstLat)); + return polygonBuilder.buildOrRect(); + } + + private static boolean containsPrimitives(JsonArray array) { + for (JsonElement element : array) { + return element.isJsonPrimitive(); + } + return false; } } From ce82ca0b1f4397ded24b2239b6cb9d6df760ef1b Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 4 Nov 2021 16:36:14 +0200 Subject: [PATCH 211/303] Fix packaging to substitute properties in package yml --- pom.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pom.xml b/pom.xml index e5ce0161ac..7503bcc4c0 100755 --- a/pom.xml +++ b/pom.xml @@ -187,9 +187,17 @@ src/main/resources logback.xml + ${pkg.name}.yml false + + src/main/resources + + ${pkg.name}.yml + + true + @@ -263,9 +271,17 @@ src/main/resources logback.xml + ${pkg.name}.yml false + + src/main/resources + + ${pkg.name}.yml + + true + src/main/conf From de1a56a4889f211894f5b62348e3ef18e675ac34 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 4 Nov 2021 15:52:33 +0200 Subject: [PATCH 212/303] CoAP ack/confirmable mess fixing --- .../transport/coap/CoapTransportResource.java | 4 +--- .../coap/adaptors/CoapTransportAdaptor.java | 8 ++++---- .../coap/adaptors/JsonCoapAdaptor.java | 18 +++++++----------- .../coap/adaptors/ProtoCoapAdaptor.java | 18 +++++++----------- .../coap/callback/CoapOkCallback.java | 4 +--- .../GetAttributesSyncSessionCallback.java | 2 +- .../ToServerRpcSyncSessionCallback.java | 2 +- .../coap/client/DefaultCoapClientContext.java | 9 +++++---- 8 files changed, 27 insertions(+), 38 deletions(-) diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index cf8c40a51c..78b25c2d42 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -223,9 +223,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { return; } transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(credentials.get().getCredentialsId()).build(), - new CoapDeviceAuthCallback(exchange, (deviceCredentials, deviceProfile) -> { - processRequest(exchange, type, request, deviceCredentials, deviceProfile); - })); + new CoapDeviceAuthCallback(exchange, (deviceCredentials, deviceProfile) -> processRequest(exchange, type, request, deviceCredentials, deviceProfile))); } private void processRequest(CoapExchange exchange, SessionMsgType type, Request request, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) { diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/CoapTransportAdaptor.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/CoapTransportAdaptor.java index b38ac3c322..0c7875aebd 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/CoapTransportAdaptor.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/CoapTransportAdaptor.java @@ -39,13 +39,13 @@ public interface CoapTransportAdaptor { TransportProtos.ClaimDeviceMsg convertToClaimDevice(UUID sessionId, Request inbound, TransportProtos.SessionInfoProto sessionInfo) throws AdaptorException; - Response convertToPublish(boolean isConfirmable, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException; + Response convertToPublish(TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException; - Response convertToPublish(boolean isConfirmable, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; + Response convertToPublish(TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; - Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException; + Response convertToPublish(TransportProtos.ToDeviceRpcRequestMsg rpcRequest, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException; - Response convertToPublish(boolean isConfirmable, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException; + Response convertToPublish(TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException; ProvisionDeviceRequestMsg convertToProvisionRequestMsg(UUID sessionId, Request inbound) throws AdaptorException; diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java index e24e14faab..d0babc51cf 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java @@ -93,21 +93,20 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { } @Override - public Response convertToPublish(boolean isConfirmable, TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException { - return getObserveNotification(isConfirmable, JsonConverter.toJson(msg)); + public Response convertToPublish(TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException { + return getObserveNotification(JsonConverter.toJson(msg)); } @Override - public Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg msg, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException { - return getObserveNotification(isConfirmable, JsonConverter.toJson(msg, true)); + public Response convertToPublish(TransportProtos.ToDeviceRpcRequestMsg msg, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException { + return getObserveNotification(JsonConverter.toJson(msg, true)); } @Override - public Response convertToPublish(boolean isConfirmable, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException { + public Response convertToPublish(TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException { Response response = new Response(CoAP.ResponseCode.CONTENT); JsonElement result = JsonConverter.toJson(msg); response.setPayload(result.toString()); - response.setConfirmable(isConfirmable); return response; } @@ -122,11 +121,10 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { } @Override - public Response convertToPublish(boolean isConfirmable, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { + public Response convertToPublish(TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { if (msg.getSharedStateMsg()) { if (StringUtils.isEmpty(msg.getError())) { Response response = new Response(CoAP.ResponseCode.CONTENT); - response.setConfirmable(isConfirmable); TransportProtos.AttributeUpdateNotificationMsg notificationMsg = TransportProtos.AttributeUpdateNotificationMsg.newBuilder().addAllSharedUpdated(msg.getSharedAttributeListList()).build(); JsonObject result = JsonConverter.toJson(notificationMsg); response.setPayload(result.toString()); @@ -139,7 +137,6 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { return new Response(CoAP.ResponseCode.NOT_FOUND); } else { Response response = new Response(CoAP.ResponseCode.CONTENT); - response.setConfirmable(isConfirmable); JsonObject result = JsonConverter.toJson(msg); response.setPayload(result.toString()); return response; @@ -147,10 +144,9 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { } } - private Response getObserveNotification(boolean confirmable, JsonElement json) { + private Response getObserveNotification(JsonElement json) { Response response = new Response(CoAP.ResponseCode.CONTENT); response.setPayload(json.toString()); - response.setConfirmable(confirmable); return response; } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/ProtoCoapAdaptor.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/ProtoCoapAdaptor.java index 1ad29524d2..e4a125008e 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/ProtoCoapAdaptor.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/ProtoCoapAdaptor.java @@ -113,29 +113,27 @@ public class ProtoCoapAdaptor implements CoapTransportAdaptor { } @Override - public Response convertToPublish(boolean isConfirmable, TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException { - return getObserveNotification(isConfirmable, msg.toByteArray()); + public Response convertToPublish(TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException { + return getObserveNotification(msg.toByteArray()); } @Override - public Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException { - return getObserveNotification(isConfirmable, ProtoConverter.convertToRpcRequest(rpcRequest, rpcRequestDynamicMessageBuilder)); + public Response convertToPublish(TransportProtos.ToDeviceRpcRequestMsg rpcRequest, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException { + return getObserveNotification(ProtoConverter.convertToRpcRequest(rpcRequest, rpcRequestDynamicMessageBuilder)); } @Override - public Response convertToPublish(boolean isConfirmable, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException { + public Response convertToPublish(TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException { Response response = new Response(CoAP.ResponseCode.CONTENT); - response.setConfirmable(isConfirmable); response.setPayload(msg.toByteArray()); return response; } @Override - public Response convertToPublish(boolean isConfirmable, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { + public Response convertToPublish(TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { if (msg.getSharedStateMsg()) { if (StringUtils.isEmpty(msg.getError())) { Response response = new Response(CoAP.ResponseCode.CONTENT); - response.setConfirmable(isConfirmable); TransportProtos.AttributeUpdateNotificationMsg notificationMsg = TransportProtos.AttributeUpdateNotificationMsg.newBuilder().addAllSharedUpdated(msg.getSharedAttributeListList()).build(); response.setPayload(notificationMsg.toByteArray()); return response; @@ -147,17 +145,15 @@ public class ProtoCoapAdaptor implements CoapTransportAdaptor { return new Response(CoAP.ResponseCode.NOT_FOUND); } else { Response response = new Response(CoAP.ResponseCode.CONTENT); - response.setConfirmable(isConfirmable); response.setPayload(msg.toByteArray()); return response; } } } - private Response getObserveNotification(boolean confirmable, byte[] notification) { + private Response getObserveNotification(byte[] notification) { Response response = new Response(CoAP.ResponseCode.CONTENT); response.setPayload(notification); - response.setConfirmable(confirmable); return response; } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapOkCallback.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapOkCallback.java index 40e1b894ee..491eea221e 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapOkCallback.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapOkCallback.java @@ -34,9 +34,7 @@ public class CoapOkCallback implements TransportServiceCallback { @Override public void onSuccess(Void msg) { - Response response = new Response(onSuccessResponse); - response.setConfirmable(isConRequest()); - exchange.respond(response); + exchange.respond(new Response(onSuccessResponse)); } @Override diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/GetAttributesSyncSessionCallback.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/GetAttributesSyncSessionCallback.java index f6e5b52ff7..f7adceec7f 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/GetAttributesSyncSessionCallback.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/GetAttributesSyncSessionCallback.java @@ -34,7 +34,7 @@ public class GetAttributesSyncSessionCallback extends AbstractSyncSessionCallbac @Override public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg msg) { try { - respond(state.getAdaptor().convertToPublish(request.isConfirmable(), msg)); + respond(state.getAdaptor().convertToPublish(msg)); } catch (AdaptorException e) { log.trace("[{}] Failed to reply due to error", state.getDeviceId(), e); exchange.respond(new Response(CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/ToServerRpcSyncSessionCallback.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/ToServerRpcSyncSessionCallback.java index fb4b855f39..ebf5547d24 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/ToServerRpcSyncSessionCallback.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/ToServerRpcSyncSessionCallback.java @@ -33,7 +33,7 @@ public class ToServerRpcSyncSessionCallback extends AbstractSyncSessionCallback @Override public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) { try { - respond(state.getAdaptor().convertToPublish(request.isConfirmable(), toServerResponse)); + respond(state.getAdaptor().convertToPublish(toServerResponse)); } catch (AdaptorException e) { log.trace("Failed to reply due to error", e); exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java index 082a94dbe6..2a1911c232 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java @@ -435,8 +435,7 @@ public class DefaultCoapClientContext implements CoapClientContext { TbCoapObservationState attrs = state.getAttrs(); if (attrs != null) { try { - boolean conRequest = AbstractSyncSessionCallback.isConRequest(state.getAttrs()); - Response response = state.getAdaptor().convertToPublish(conRequest, msg); + Response response = state.getAdaptor().convertToPublish(msg); respond(attrs.getExchange(), response, state.getContentFormat()); } catch (AdaptorException e) { log.trace("Failed to reply due to error", e); @@ -466,7 +465,8 @@ public class DefaultCoapClientContext implements CoapClientContext { try { boolean conRequest = AbstractSyncSessionCallback.isConRequest(state.getAttrs()); int requestId = getNextMsgId(); - Response response = state.getAdaptor().convertToPublish(conRequest, msg); + Response response = state.getAdaptor().convertToPublish(msg); + response.setConfirmable(conRequest); response.setMID(requestId); if (conRequest) { response.addMessageObserver(new TbCoapMessageObserver(requestId, id -> awake(state), id -> asleep(state))); @@ -527,7 +527,8 @@ public class DefaultCoapClientContext implements CoapClientContext { String error = null; boolean conRequest = AbstractSyncSessionCallback.isConRequest(state.getRpc()); try { - Response response = state.getAdaptor().convertToPublish(conRequest, msg, state.getConfiguration().getRpcRequestDynamicMessageBuilder()); + Response response = state.getAdaptor().convertToPublish(msg, state.getConfiguration().getRpcRequestDynamicMessageBuilder()); + response.setConfirmable(conRequest); int requestId = getNextMsgId(); response.setMID(requestId); if (conRequest) { From df08320eea06c1617c3d3f1cfe33c244be05f068 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 4 Nov 2021 18:05:13 +0200 Subject: [PATCH 213/303] UI: Fixed not load advanced settings in widget --- .../components/json-form/react/json-form-ace-editor.tsx | 5 ++--- ui-ngx/src/app/shared/models/ace/ace.models.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx index dc5402c044..12879d1fae 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx @@ -20,16 +20,15 @@ import Button from '@material-ui/core/Button'; import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; import { IEditorProps } from 'react-ace/src/types'; import { mergeMap } from 'rxjs/operators'; -import { loadAceDependencies } from '@shared/models/ace/ace.models'; +import { getAce } from '@shared/models/ace/ace.models'; import { from } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; import { CircularProgress, IconButton } from '@material-ui/core'; import { MouseEvent } from 'react'; import { Help, HelpOutline } from '@material-ui/icons'; -import { position } from 'html2canvas/dist/types/css/property-descriptors/position'; const ReactAce = React.lazy(() => { - return loadAceDependencies().pipe( + return getAce().pipe( mergeMap(() => { return from(import('react-ace')); }) diff --git a/ui-ngx/src/app/shared/models/ace/ace.models.ts b/ui-ngx/src/app/shared/models/ace/ace.models.ts index 9a3c30766e..3b088e01d3 100644 --- a/ui-ngx/src/app/shared/models/ace/ace.models.ts +++ b/ui-ngx/src/app/shared/models/ace/ace.models.ts @@ -22,7 +22,7 @@ import { map, mergeMap, tap } from 'rxjs/operators'; let aceDependenciesLoaded = false; let aceModule: any; -export function loadAceDependencies(): Observable { +function loadAceDependencies(): Observable { if (aceDependenciesLoaded) { return of(null); } else { From 5764287a1242f959a64245b7a0b8369dd614a420 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 4 Nov 2021 18:09:05 +0200 Subject: [PATCH 214/303] UI: Improvement trip animation: fixed calculate start/endpoint; fixed update current position --- .../data/json/system/widget_bundles/maps.json | 10 +-- .../components/widget/lib/maps/map-models.ts | 4 +- .../trip-animation.component.ts | 80 +++++++++++++++++-- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/maps.json b/application/src/main/data/json/system/widget_bundles/maps.json index f6b4d75c3a..4a2e315595 100644 --- a/application/src/main/data/json/system/widget_bundles/maps.json +++ b/application/src/main/data/json/system/widget_bundles/maps.json @@ -18,7 +18,7 @@ "resources": [], "templateHtml": "", "templateCss": ".error {\n color: red;\n}\n.tb-labels {\n color: #222;\n font: 12px/1.5 \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n text-align: center;\n width: 200px;\n white-space: nowrap;\n}", - "controllerScript": "self.onInit = function() {\n self.ctx.map = new TbMapWidgetV2('tencent-map', true, self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.map.update();\n}\n\nself.onResize = function() {\n self.ctx.map.resize();\n}\n\nself.getSettingsSchema = function() {\n return TbMapWidgetV2.settingsSchema('tencent-map', true);\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbMapWidgetV2.dataKeySettingsSchema('tencent-map', true);\n}\n\nself.actionSources = function() {\n return TbMapWidgetV2.actionSources();\n}\n\nself.onDestroy = function() {\n self.ctx.map.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasDataPageLink: true\n };\n}", + "controllerScript": "self.onInit = function() {\n self.ctx.map = new TbMapWidgetV2('tencent-map', true, self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.map.update();\n}\n\nself.onResize = function() {\n self.ctx.map.resize();\n}\n\nself.getSettingsSchema = function() {\n return TbMapWidgetV2.settingsSchema('tencent-map', true);\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbMapWidgetV2.dataKeySettingsSchema('tencent-map', true);\n}\n\nself.actionSources = function() {\n return TbMapWidgetV2.actionSources();\n}\n\nself.onDestroy = function() {\n self.ctx.map.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasDataPageLink: true,\n ignoreDataUpdateOnIntervalTick: true\n };\n}", "settingsSchema": "{}", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"First route\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.5851719234007373,\"funcBody\":\"var lats = [37.7696499,\\n37.7699074,\\n37.7699536,\\n37.7697242,\\n37.7695189,\\n37.7696889,\\n37.7697153,\\n37.7701244,\\n37.7700604,\\n37.7705491,\\n37.7715705,\\n37.771752,\\n37.7707533,\\n37.769866];\\n\\nvar i = Math.floor((time/3 % 14000) / 1000);\\n\\nreturn lats[i];\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.9015113051937396,\"funcBody\":\"var lons = [-122.4261215,\\n-122.4219157,\\n-122.4199623,\\n-122.4179074,\\n-122.4155876,\\n-122.4155521,\\n-122.4163203,\\n-122.4193876,\\n-122.4210496,\\n-122.422284,\\n-122.4232717,\\n-122.4235138,\\n-122.4247605,\\n-122.4258812];\\n\\nvar i = Math.floor((time/3 % 14000) / 1000);\\n\\nreturn lons[i];\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Speed\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.7253460349565717,\"funcBody\":\"var value = prevValue;\\nif (time % 500 < 100) {\\n value = value + Math.random() * 40 - 20;\\n if (value < 45) {\\n \\tvalue = 45;\\n } else if (value > 130) {\\n \\tvalue = 130;\\n }\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"fitMapBounds\":true,\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"tooltipPattern\":\"
        ${entityName}

        Latitude: ${latitude:7}
        Longitude: ${longitude:7}
        Speed: ${Speed} MPH
        See advanced settings for details
        \",\"markerImageSize\":34,\"useColorFunction\":true,\"markerImages\":[\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7b13uB3VdTb+rrX3zJx6i7qQUAEJIQlRBAZc6BgLDDYmIIExLjgJcQk/YkKc4gIGHH+fDSHg2CGOHRuCQ4ltbBODJIroIIoQIJCQdNXLvVe3nT4ze6/1/XHOlYWQAJuWP37refYz58yd3d6zyt5rr1mX8B7S5Xo5/0nPYaNFM1PY0gGqOhfAgQCNBGlWFFUAYEIeihigbhFdZQwt85BV5Gj9r/718R2XX365vFdzoHe7w6d77xnPkn4YpAtU0YiizNJcmPNkMQFkDiSlowHt2HNtGlTSJ6B+pTpsKTfKgTj3Pi8SMtFtEZnFs8d8dPu7OZ93BcCHtt0+OiL+FJjOiqy5K5dtLwD4PBHGvy0dKLYo8B+1+lAldv50FfmFzWX+84i2M3a8Le2/Dr1jAKqCHtl2y1wC/pEMP9ZRLBaYzF8CCN+pPluUkOKfB6qlmk/dBwTyt8eOv2AZCPpOdPaOAPjA1h9/SJX+TyGXuz0TZi4EcPBeOk+U+RErZh2YyMAyQJEoZUjFgtkCAEScgDyx1hmInTglqDj2U1X0WILaPbWvwHO1WummeuLONhaXHTf2wsfe7rm+rQDe133j/i5xPyrmCr+OouhSKPbdQ5fLiezTIYUBQGMJBgYWxMYSISZhbxgQT8wGAgDiwWxUvCiBxKhSKOqdh4OyV5+6XiEfK/kjVOXQ13apG+I0+adKpXaG0/Si0yZdvPbtmvPbAuCNT98YTBhT/8fAmEpHoXgKgPe/6gFGP0nwG8s2YykcaRCAYYQ5tKTkDVuArDEwMRF5AICS4VZ1AQBSr6oEgL36CBAvlKqIsyLOKQl5TZH4uN+TawDuY6o64lWTJX20v1S633uJNvfmvnbRERelb3XubxnAX26+5gDy6Y9HtrU/wERff1XjSt0WwULDmZEMawPOgilgQ4FaGCEygaXQMQyRMaxiUijUkAEAImIGAFURAOrVA1AmI1ZExGuqoqkVFefhyGtKDql4X4eHc6LxJof0VIVM3nVc4uXaHUPlo0Tpc2fv/zer38r83xKAd6y74iImO31EMf9REA7cpdVBY8NbA5+dFNqsCTQipkitBjAUsLUZNd4qm8AyjDMmJAIRhDzDEBEbJkBVAyJWQJ14AEaciIeSGicOgBeBWNHEeXLkXIM8UvFI4bVBCVJNfdk7STd5xOcp0LZzjIqV/eXq/4i61edM/eaN7yqAqpfzf62Nf5LP5lbko/DbCuxU4saEN1mN2kKTzQbIkuEIEWfVagRDEVkOyXCkVq0aDg2p9YYNAySVerU0WN1R27Jjo6ulMQ1V+ggAOgsjNRNEus/IiUFnYUy2kM23AcrivXh2RiTxjhx5iSmVWEWdpmhQ4qvwSBBrXVPfqDmuVsT7C3aZvKslyZcr9dpxdr81F8ynO/w7DuD1q/8y6kDw2872ticN0deG7wvQHXHmdxGK+1ibQag5ikweliIElNUAEayNYBCSRQRiYzf2rNtx11O/rC5d9dj+1aQyM2Pyz3WGozaNisYNWY7SYtgWA0A5KUVO4qAn3t4+lOzYt+Grh+bDwstHzvjA2tPfd1Z+39FTRhGpi7VBKrE4nyBFDKcNJL5OCerqUEXdVeEQb0mk8lECjR0euxe9cqBUOnoQ6RkXT78hfscAvH71X0Z5kf8Z0dH2CgNf2NkI0d0ZbmtElMtFVEAQ5BFIlkKb00AzFJqCGooQcJjv7t868P3/ubayZvua48ZlJt57xLjjB/cpTssXokK7IQNrbeoZ3pIRJm1aYSUW9cwixglZ7xNU40ppY7mr+sy2ezt7G1s+vP+EGfd/+fS/Ko5pH9/pJK04X6MUDSRapcTXkXJN46QKp1UkqNVqvpxVyLzhOajihh1DpVkmrJ7+uak/bbztAF6/+i8j62p3j20vbgXR+cP3LYU/Djg/KcsdEnIWERcRIk+hzWtEOYSch2U76tk1T6+84Tf/NCdni2tOmbRgy6T26WOiKDBhGFEQhrBhiNAyjDGiQp4DFgI8AChg1BGBXOC9p8QJ0kas3jvEcUxxnLgNpTW9izfdOqGWlve7+OOXrThk6qEHKtKehq9xIlWkvoaYytrwFYqlglgrcZxW+oXSz+ycpOLmnsHypDTIfuTNcuKbAvD2288x22dn7hrVnt/ATBftBE/CH2aCtqkZU6CI2hHZomS4YCPK+5AKHFB2ZNe2Nev/739/e9qY3KRnPzHtQp/LtnfkMhnKZDMa2oDCTIjQhghDC2MCCQITAyYxpmkhAIAZDDA7l4bOSeR9YpLEwfkUjXqMOE0QN2LU4waq9aGBX6/+d7O9sXnu3579jbVTx02dlEilL0FDG1pJG64cJX5IGr6MupY5duU1npIv7sTQ4196ytUDx8+sf+TN6MQ3AyBd8+L8W0a15zYw0d8O3ww4vC7ijlkZU5QctVPE7QhNEVlTRNYUjHcy7tu3fuuVSqXBF8z66962fMeIfDaHfD4nmUyWsrk8BdaYIAh9EFoxzExEysYoAQ5A0ioAEIpIBGZmAM459iKaJo6cT209TnyjWkOSNLRWi1GtV9A3sGPg56uvG1vIZ9N/OO9rM8jS9oavSOwqaEhZYh3khq9K3fdpXWsbvdR3MoYCV/UOVadcOvv2C/AG9IYAfue5j1/U0R5mIhNctxM8yvxLyMVpOduJyLRRnto1MkXK23axlB27sXtT1z//8vqDTt3vk/fMGnX4xGyhiEI2Qi6X1Ww2S7lCIQ3DkCxzQEQKYADANgCbW6UHvwcRaO6fAwCjAewLYAKAcao6UkRIBEniEtRqNVOrVKjeSFCP61oaqurKvqe237P2lnkXn/X/PT9l3OT9Eql2V90QN1wZdRqSuhukhi9T3Q2s9ki+NDzHWppeUqnG/qsH/+b7fzSA33ruI7ODIDh/RCH6KkEZAEINfhia4n4ZO0KzphN5005Z06aRaeOAcjP++4Ff3P/86hWTLjr08i3FfEeurS3LUTanhVwe+XxOwjAw1loLoB/ASgBrAdSAV232Gc0NyJGt70+27mlrzNT6nAEwDcBMACO892kcx1KvN6hUqWu9Xka9XsfgUP/Qjcu+Nf3g6bO7zj7urBNT1F+quxLXfUkaMmDrviQ13+8THdqYqvuLZpfq+qrJNXFDbrp87t0v/cEAXr5iduiTMQvHd2QnKDC9+bC9NUfF9kwwgvNmBGW5Q3O2SFkzAkaCg/71Nz9+2MTZ6rlzLs4Vi0WbyWS5o63N5fM5G0VRaoxpA7ChBVw3ANMq1AKoHUAewCwARwHYvzWctQCeaNUrt4pvgeha17Gtevt47+M4jrVSqZlSqepqjQpVyyX/8xU3VBHF2T//+OeOFbgXaq5fa75ENR3SarzDxDToYz846FTORbPRV7oHG9sm+qEPX3TEM3vc9pm9AfiBP53+T6Pbwo0Cd4aog4p/yXK+lDX5IDIFZDinGS7CckEM+JB//u9/e3Z8NGPTgjl/Maq9s8N2FNtcPpc1bW1tFIZhaIxJATwFYA2AtAVWh4hERBQByIgIE1Gsql8gou8AeAjAfQAeVdUvEtE9reFFIpIloiyATgARgCqALQAGmHmUtTYTRWHDhhaGYE0YYmbHEXZj//rBRc/fXTly5qGHEus2FUceCbxP4DShRJ2mvuIFboyqG5kNcNuWVM965MbNd71pAC99+vADA+MnR6F+TeAg6h1TeE/I2bbAFjVLBbJcpIDzZNke8qNf//yxKblZWz42+9Pj2opFbutop7ZCQdva2hAEQZGZXwGwDEBDRCJV7VTVfVV1BDNPUtXZqnomER2tqi8S0REAzgJwUqvMI6JBAM+p6pdU9f1ElGu1E6lqUVVZVYWI6gA2EFFijJmSiUIPsDbXmGT3b59V6Kv0dd334uLGYTPmHK7Q7lRi65DCawqviXWSrEm1PlvgWMh9KPbut+/77Ohtj/97d98bA6igo7aM+O/Ogp0l8BNFPQhyY2RyE0MqcC7Ia2jyGpksBYj2//WDCx9uk/EDZ8783JhiW5HbigXpaG9HNpvNMXMGwAoR6SWiUKS5KhERS0QqIgmAHcz8sqrOA7AdwCcB9AK4CcBvAdwP4EVV3V9VPwGgC8B4Zv4PIqqoqgPQYObEOadExC1A60RUJaLxURQaZqoRW0NEsm/xgI6u7rV9L295vmvGlKmHQ32vk0QdxfA+oYTq+Vgbi70mR4p6BEaKlTid98S/9f4MV7wBgF/66AEnFbPUz+z/VNTBiywLgxxCFDgwGQqR5wznOeR8+6p1657r6uopfu7wv4mKbW0oFvIoFovIZDIBEXkReUlVG6o6Fs2N/EjvfSczj2Hm/YnoY6r6Ae/9w0T0cVXdSkTfE5FsC8iTAZwI4DAAjxDRj0TkUABTACxS1csAzG39MHlmzqvqGCLKt1xZA0Q0QERtQRBkDZMngrcmNAeMmB08uHpxNsrz2pFtbft4TWInDZtSLE5T8i7uSKRS8XDjBX4fYbnusI2jMkt/tGP9rnjxrl+gICP4Riagrzb1ssKa4CkrYRhwwBFHYGSUOZJKo8oPP/vCoV846opSoZCnQj7HxUJRMplMgGblR5h5wHtfbE1oZAvIHBFtVtX7RKTQ4pSrnHOXAThQRK4BcIaqNkTkRRF5UVUTVf1462/TVPVSEfm2974qIm3MvBhAl6pGAEYAaBcR45zLiUiPiDxKRC6bzZpsNhtGUaj5fIG/dNTltYeeWja3ltbVcGgMZX1IWbUUqDUBbBA+OYxDPuDLSORq6KsN76s48MvzZnwwlzNDgaFzAIBAi0LKtGVtEQHlOaQCQpOHoWDWL+9+ZODCuV99cnTbmM5cIY+2JudZIpronHukxUWemavOuZIxpuG9H8fM8wDMJaJHVfV0ANcDOIyIPg5ghTHm+0S0UETWq2oCoA/AI6r6C2PMgyKyD4BPM/MggJ8COIGIFqnqV1T1YADbVXUjEfUaYxrOOcPMBVXdCmCutbZirQGIlIBwavucl2577NaJM6ftO1nJ9aY+YfEpvDryknamSNdAMQ1AGwxdc/DqDjz9k/7Nw5i96ixBSK/MhTRxJ7oUbracmWAoVGNCtRSCYOxLazfcN7VjdjK+beK4KAqpkMtpJpNRABNVdT2AowHUvffjAYgxZpNz7hUiuk9VT1LVWFX/iojuBfA1IrpfVRcS0Xne+6tUX33+M/zdew8AzxljLvPefxTA3xPRIufcpQA8EYUAFhPRSCKaKSL7EFGgqjtU1RDRZmaeGIbh1sh78s7LxM59R09um7585fqNdtqUMZOMMc4igE0DthSppcYWL80VTNbyX1QCPgNN1fJqDvzi0tnjQviObGia3Ee0JEAml+E8DOUo4pxaE4GUJz3yxJr9/vSIv+8uFAu2kM8jl8vBGNNJRE+q6grn3AZV3QRgi6q2AZjHzHNE5FEAp3vvv8HM8wFQSywvADAPwDgAi0TkPwDcBWDhcFHVh9FcXH9ARE4BMI6ZvyEiHwYwSVW/CeB0IlpERJeo6hwiepmIlnrvVzLzemZex8yDzDwZqlUikGGm6R0H66+evuPYafuNynvFkCCF4xjiBd67otN4C4GmEDAqTuVnR3++beWT/z5YfRUHio8/0dEe7DynJTUvswmmEiwxWcCDwGyee37j4ydNO6ucy+YmZMJQM5kMWWvHqmqPc24eADCzENEGAMvTNH2AiM5Q1W1E9GkR2cLM3yOiS0TkO0R0lao+zMy/8N7PBHAmEZ2C3YiIoKrdqnqjqq5i5j/x3n8bTQt8iapeKyKbjDGfFpEhAGOccw8EQdBhjPmQqk723rP3PrTWvhxF0Xgi6vHeayaTyx075fS7nlvxcPGgg8ZNIjHeSKRMdbEUIEHwEuCOA4DOvB25vSRnAfghMGxEFNRb7ZoM0HFNadFeIjvRgMFkhEDKbEl8Oqq7u3bs+/c9cXQUWo2iCGEYsqrG3vvHAPwEwL2qulZETnXO/Zm1FqoKVf2Bqh6qqr8SkW3e++tU9T4i+ntVnem9vw7ARQA6ReQ5AL9yzl3vnLsewK8APIfmovkiIrpWVWeo6t977x/w3l8nIluI6Dcicqiq/quqgpnJOfdnIvJR59wmEVlCRD9S1QeJKLHWmmw2hyAM9bhpp47q7q4d733aSVBlkBoNQGxgYPdVRZ82N5In9lS7dp42GgA483hMyUY0RXgwXzAjQgUtshp1WhOR5YgDzoiB0U2baqsPLB7z0oxxBxWz2Rxls1lh5gNVdbn3/rwWR68moi5VPZWZt4nIvgBGquoRAH5BRH+OprH4oYh8XlVPQXMvfIOI/BJAFxF1qupxRPRBIjpKVSe3dOtdInKbqj5PRIe3RHayiHydiMYDOIuZfyIin0HTfI4kIgAYa4y5UUQaAI4QkY8ZY5YR0aGq0kcE8k5NNS4t665u6G9r47xDCi8pqabsNbFe9WkoRvU0upYl8GunnqebX7kZQ00O9DipLbKjRfQTPWnXYyBTBxMBBiIML2IVkt20sf6B46d9rJjJ5chaQ0EQRAC2pWm6VlVXq+rZIvIXSZKELcX/Y1U9RlW/AWC8iJyqql9V1aOcc99W1SXMfAmAh1X1qy3O+rKIHCMiGRGptUqude9iIrqWiC4brisiDxHRt1X1KFX9qnPuowDGe++vUNUPishNLQkIiOjPVPVs7/02EVkLYHsYhtYYg0wm1FNmnZPftKF2lFPJisCIkhE1DFiFaNLr1i5R+PntGR5lFMcBLWfCxxbhrgkjgqMAjCKgkrWFX48KZ7RHJm8CziJLOXJpUNu4omAuOfbKOMxkKBOGHIbhHBG576qrrtLHH3/8QmaOdtdd/5tIROLTTjvtyc9//vN3BUGQs9aOA3CyiDxXr9dRrzfo2gf/Ljt1TpyYIMnWtQ4nVW2kNd+bri41fOlMADkQerb1p4/f+WGcaS9X8HOLUQIwCgCUdFGi6ehBt7k+3k4DqQ8cOd2+mQdPnP6xijHB+MAYhGEoqppL03T/J5544iRmpvnz5z+4Zs2a1dOnT5/+8ssvr5o5c+aMWq1WSdM0VdXORYsWHW+tXXbmmWcONV2jQG9v744dO3b0jR07dvSIESNG3HbbbbNFpHPBggWPtMTvVUREWL58ee2VV145bcSIEU+ddNJJ1RY4unLlytXTpk2bEoZh2N/f37dw4cKTrLUdxWLxvnnz5pnf/e53unDhwhPa2tpWnnfeecekabopCIIMEYGIyBjGCfufvmbpltuKY6a4LKkzCh8PpZu913g0oIsAOhOKMQTElyvYPrsY43IRP6uK8wCAYHrUo+gpiXoaG+LR0X5VaNgxNEAHz5pz6PIgMGBmBTCKiJZVKpUjjDEmTdPG/PnzPwSgLCJHoLlY/omqXgLgWSJauHjx4uNPP/30obPPPnsAwGNoLl+O32Xdt/a3v/3txnK5HM6fP/+3aJ2JAAi89zkAUwGcdOqpp+YvvPBCnH322fEJJ5yQA3CH9/5YY8yft0C+SkTmP/roo72NRqPjhhtuODCTyRTPOuusRy+88MJVd9xxx8cWLFiwiog+oqp3ARgVBMEO7xVzJ70/v2jdHbNGqu/16uq98WakmuQgANhsU98MRQwMP7N0iYxhUuybD/n3WzqlAMROROElzfY3NrXHrtTNFHTkMvkiGQNiZhGZ7ZzbPDx5IoKIXK2qZzDzd9F0T/0pEV2qqoeKyN8BwLZt27ap6hmq+l0RmQXgZhH5iohcpaqrwzA0RATn3DXOueta5buqeoWqnqWqT9dqte8DwPbt2zeKyBGq+l1m/giA7wL4map+jYj2S5LEA0AYhp0AvsvMp5577rn3Axi/YcOGxaoKEdkCYBYzqzGEMMgUWILRjXSopzfekFUf5wUKYXYQCoZhykcM08C+DMUMw7Rva8sHqHZCJFD1VtTDaYLuoe3xrLGH/Yu1NiZVtcYAQEVVy7vpmPNU9VHv/RUArgZQ9d5f473/qYj8OwBMmDBhPIBnnXNfAfAj59w5AK4F8DURmcfM1JrY/4jIrSJyq/f+XlV9vmVMPlEoFC4GgM7OznEicmPrB3hJRC4Tkc+IyI+897cFQWBay5lrVfVKVX30lFNOOUZV/aJFiz7YMi79RFQiIgbg2NrazHEHf7+70q1eGiwkROoteQkhOmIYp8DQBGUcYIVwOJMepCCAkBCooCAnUPVwXoU1rrXVoyi7nwgoDO1QyymwzTn34d7e3p8B+NsWFx4AYLP3/l4iuoKIHhaR/yaiLw1z6rp169Z57+cR0bUiAiIaVNU7ReR5Y0xcrVbPbf0ek1U1DwCq2qOqG4jofhHZUi6XAeC7IkIAvqCqIKItaG4LZ4jInxERvPevtK5fY+b7W+0eBGD78uXLx6nqd51z85i5G0Bore1rNJJsxuan1EumFo3w3mtKSupAMASNRJEACBk6ixWphWCaKs1tqegVUIWyiBcPIYhRQlLKhQccNDtW9YEIh0TkiciJyGFtbW29LfCCxx577PtHHHHEhdbabd77bzLzFap6jPf+X5o46Jf333//qWh6kP+P934HMx8F4HQA53rvkc/nl9frdYjIQbsw99SWy6opPvl8BQC6u7u3ENFfq+poVb1IRK4iIvHeX7dy5UpKkuR8Zka9Xv9WNps9n4j2B/DNkSNHnrV9+/ZRIvIhIjpMVZeoqlfVEcyQ6WNmpQ8+nyva9m4IO/XeQ1XFE6UKfYkUhyrTEVDEFkAWO4NuZAuAsPnDKlgFzih8ku0cU5y4NQiCxFrLAPYDUCOizxpjrgAAY4y54YYbvtwS5f1E5B9UdSgIgloURR8BIESEO++8c8qmTZtetNYeHYahdnR0wHv/pIhsrVarvX19fQsA5H71q1/dYq01pVKpkCRJXCqVaGBgwDcaDdfX1zcRwDELFy788JIlS96XJEnBOQcADSIKmfkSIsKwpXfO/bmItBljLlHVa6dNm/bIE088sR+AMUT0WRG5kIgmWWtfIWPcuPZJDJ9r90hIRVTEq5KAlBIIdYH0UCg6FMhZUvDvjSDVnZBhUhUSUijICxHCbDFXZGOMqKoH0KmqQ/l8/ptdXV0/rlar38rn8zs5hJmJmUM0jyPb4/j3h/ze+ylLly6dgr2QaepX3Hnnnefv7ZmdoyUamyTJWABoHvTtmbq6un4xa9asSQCuA7DSWvtSo9E4zHt/dbFYvKLRaKwF0E5EwoBENlKVMOPFkcJDCRBVUlEloLQTLgWz1987FAhImCECJVEh8Z6cdzBk20ITkIg4Y4xX1ZFoHuJM3XfffT/S29uLLVu2oFKp7HQ9/W8ia+2RzHyGqv6TiPzjsccei97e3kxbW9uZACYTURVNb7mIiIYmJIOwLUWqTqQVIqFEDFHV6nC7orDMBB22LOzhWbRC0LJRLalqGYqyQWAJVDPGVJIkqQPYrKq9AGCMmQoAaZpix44d2Lx5M/r7+5Gmbzn4822jVatWvei9/9M0Ted77/9j5syZawAk27ZtswCgqt0AtohIzRhTssZWDdvQkA4RtETaxAOqZSWWnXgR1Kr8/kTbG2ThtaAE9QQSZWIQ2EilFteyhoJCa4lxYMvf9xry3qNUKqFUKiEMQxQKBeRyudcVsXeC0jRFrVZDtVrFzTffnOnp6Tl2/Pjx944ePXrt9OnTzyGirY888sjLCxYsOERExhPRDGvtswACrz4m60pOqIMIBIX4ZqCYAWsZLXumAtid6z8A5DSvlgkKFkcMiBERqHUDiUu8994SkQCoEFF+jyPfhZIkQX9/P/r7+xEEAbLZLKIoQhRFbzugzjnEcYxGo4FGo/EqCejp6Tnv5ptvfk2dH/zgB8sWLFgAVS0CqHjvyTlnq2mFYF3VORnJICKwI2IFI0Qi7TCtLaYCVgnbAdoA6GRhaoPXhipIVJkEUCXP7CrleBAd2RHsvYcxpopmfMreaICZN6LpQWYRmZSmaeeuk7LWIggCWGsRhiGstWBmWGuxqwUFABEZ9ilCROCcQ5qmcM7BOYckSYbd/XuiTczcT80YHHjvZ6MZZ4O+vr5hx+14Va1Qa/M9WB0Asa+SUCcIRuAtg5QEBKDYrEJrwdhiIXhBRQyIJkMxQxQvkELh4RUq4kCJ2VHdOLiOx+YmmTC0trWwnQOgsvtoiegFInKdnZ3rRo0aJT09PTw0NAQAm0VkzvBzw5N/B0mMMU+pqhk7dmxXsVjkzZs35xuNhojICDSPRpPt27c/WSgU5hLRC95722g0aOPgWnbcW5VUBYCSJYBBChgQzWnt2J4BsJyheFkVr7Q6Hc2kZYU6ARSejCjZFN259UOrc6reOucMEfWpqnXOPQIAhULhN8PgMXNl3rx5Y4IgOIuZz46i6KyTTz55JBFVmXnFO4nYrmSMeTKKooEPfvCDs40x8621Z3d2dp566qmnxsxcArC1s7PzkVWrVi1X1QBAv/eeiYg2DK0upOgpiCBQIlIBBOrBOgTCCAAQ0jUQrGS1WF1vUPewLlTlKoQCOARewOqVUgzmtlXWTWuKiqiIVAAgjuOtuy1bgtNOO21ET0/PhO9973sQEXznO99BT0/PxJNPPrkDQAO/97C8k7RBVaO5c+ce19nZmb3yyisxZcoU/NVf/RVWrFjx/kMOOWQ9M3dXKpVRjUYjbKmGinOOnPPYWt04PZGhjHoQCZigAQsFpFwbxqlRpx6k6LI6gK5Kpz8zm20d0JHWQFAYTSUlALDexSNdEB+Y+nQxpZRlppSZ4ZybdPvttz9QqVSOt9Y+SkR+xYoVxx522GF4/PHHceCBB2LZsmWYPn06nnrqqQOZ+REiekZERr+T6BFR37hx47rWr18/NwxDvPLKKygWi3jhhRdw5JFHolarzXvuuee60jSdYFordxFJnHNI0rghiGc4jb3xUDEQEngyYEBrwx7KcuJHZzux1t79KZQ++iv5AHTnCadVBZGQhULh1SsIMfoe7KlsGRqTm5Q1xmkQBJtV9dijjz766f06bwAAEgVJREFUnpUrVy4EgIMPPjh300034bjjjsOaNWtQqVQgIjjqqKOwZMkSzJs3b/Xy5cstgFUA3rZF954cr6eccsrYxx57DJ/85CexcOFCDA0N4cQTT0S1WsWjjz4azp49+4l6vc5Tp049TVU3eu/hVXVbZUN/TH33k8c4DVRIiMFEohCjCIdXLC6VY+44DV+zACCEXiiWgnCkEp1EpKsEqqTEIsTq1Axg+eCy/kczp+QmqDZfuXpRVedNmjRpx9VXX32hiEBEsHTpUtx5551YsGABnHM47LDDcNNNN+GAAw7Al770pc8NPzdsUXe1rsOA7n4dBmjXK3NzgbHrZ2beWQDg7rvvxq233oqLL74YS5YswY4dO/Dkk09i7ty5uOCCCz4bx/FPRGSUiNydph71ap2W9T9eGGgsr4iqZSVVsLJ6Z5lIlU5srfmWAlgHtE7lDjgP5SjgAWb6MBTtoroMgpwoERTwniiJhwq5aPrxB+YOWwuQIaKEmWd573NBEHSoKosIpk+fjltvvRWqitWrV6O7uxvLli3DV77yFRQKhVeBtzcgd/2+exmm3bl3dy4kIowfPx4LFy5EpVLBpk2b0Nvbi+7ublx22WWw1ro4jgsARgJYVq/XUG/Uk2fK95+ypXxfrESGGUIEMhYGTP1ovQOYOr2+kcjvVt+K9c130cp4slyX4nDnBqYbRCAGkTZXUELIVtPeezeUu3rjOEaSJFDVpwEcmKbpLcMTnDhxIm644QYEQQDTPDvBNddcg3322ec1IL1e8d6/qryZOruDffTRR+PrX/866vU6kiTBAQccgOuvvx5hGKI15hki8lTz76lura/fUUt6F4siJIKCiREAakhB6BnGp1ST9lwbngJ2CfE99Zd4cPzIcDqg4xl4wQl64EE+BlyicCnYanHz4RMumviR9vO7C4UC5fN5JqKzVfXlKIomtzzGr5nwGwGwOxe+ngi/ntjuXowxe/s+0Gg0+ohofxG5o1KpoFqv6+LBn496dssPt6dcmWAtlCOCNRDKgJgxEopDoLRl60Cy5p5P4Hhgl/A2NbgmTuUGBeCBOUTokVZAtyiIFJSk5QmJlJKeyvaeer2u9XpdVPVxVZ1Zr9dv25PI7Q7M3sDbEwe+0Q+wt/b21vdwqdVqv1XVaar6eJwkqNdj9JY3bW9IKU5cZRwUDNPcuagBE2G7Kg5RAKnI9SD832HcdgJIARYOVdyknXtjoTpBoaRsTPOMHQy7fMutQy/qQzOr1arW63VNvd+kTc/NfO/9I3vTXXub0N5E9/U+v57Yvp7+VFWkabpYVc8DMJSm6aZyqcSNRk1fxOMHPb/5v+pQtWwgUBCxErGCiOJhXHYMuRkU4r7XAHj3aYhTAaC4rakI9dNkMMSWPBhMSsRKmjRKIyuuZ3Bzfe32crnGlVJJReQ+Vc3HcdyuqgPD4re3ib1ZHfhmVcDuYO4JxNaYetI0HYvmMen91WqVqo1YNqVdW2uutz9NSp3KTNpcxMEYgjEYVNULmvVxiwLVu09D/BoAAcAZXL6j7F9SBVRgiUwPkRJYCQaqrEoMWrrqp4WN2ZfmxXGtWq7UqFwuJyJyP4A5cRw/qKryelywNw7ck+58I336ZvtR1Uaj0XgewMEicl+5XPblcpXqtXJtk33x1KUr/6MAbnKdgQKsDFUVMTtUYFWBvpLvohRX7orZqyJU192K6tSz9Qv5HPcQaCpBZyvjRSiyEFIVkDioiBbL1W3LglGduWJ9LKDExnAtCIJEVU/w3t/MzIfsbiD2dn0jHbkrF+1qSPZkXHY3MMNX59ydaB5ePdNoNLZUqlVfrpSxOvO4earr5xvqvm8iGfggBFNIyiGYQwwQ4xwABqqLhmo+c885eJVf7NUx0gDE4iv9Q/JYc1+MDABvDJQs2DDYhlBmxD2Da6YNxOulW9dsr1TLWiqVtF6vrwawXFU/7Zz7TwB/FCf+MUuW1ylJmqY/F5GzVXVZvV5fWy6XaahU5q26asuA22L7hlbvR4a8NVAYKFsgMBACJZDm7mNHSZ41HpfujtdrovS7bkV58p/oRwpZ8zIIhwM0C0SLoBipCmqNnaHAhq3L7MT9D9mfhjIrrYRt3nu0fG9VAKd673+Npq8t82a5cW9ADdOb4bZdljfbRWSpNt9BeSJJknVDQ0MYHBqiwXRHd9+IriPvffpa4YBCE0I5grCFMRlSGFoF4DMt3ffDUtXLPfPxyzcEEADGnoNH01gWFLNmChQhgTJEOqiKQIQEAiPNU09+Zf3jfZNnH3yY9mVWasoFL16sMWVm3gzgNO/9KiJaq6qTdlfyewNv9+f+QNCGPz8qIgLgaFVdVK83egcGBk25UtWBel9f/4Q1x931yFUbYLWNIxgOoDYgDSJYE6IB8CEEjFKg1D2QdscVfHn9r/EaB+YeAdx8B9z0+Sgz8HxgeR6AMVB6hgzaVMk3Q/2JSQHvJOra+GTXlMPmfEi6o+d87NpTLyTeN5j5ZWae6b3fV0RuIaKZqmr3ZJ33BNzuAO4G0B7vMfOQiNyqzcBN8t7fN1QuN0pDJVQqJe2v9u2oTt9w0l0P/uNz3iQjghA2CMmEGXgOCSYDIqJuAk4AgHrDf7We6u/uPx97zO6x13fl1tyOtfucqRcXM+ZFAHNAmA2iu4gwRkBKos0jAVXy4vKvrHvslWlHHHZk2m1eQKJ5VfXOOauqG4Mg6FXVj4nIalVdpKoHqSrtsrzYed1VXAHsDaQ9caAQ0S0iMoqIPkBEDzWSZHWlXI6HBkvBUKWsQ2nf5uSA7SfeueTqFxPUxtpQAxMSmxBqAhKTBZhoBYALAUCBW3ZU/D6Lz8E1e8NprwACwKQv4nf1fvlUMWsJwEgC5oDpIVJ0EhGrJ6sAICCXuvYVqx8uzXj/YZPSWFbWelyHeA/nPRLvqwxa3XRN4COqugrNKPwx2ozifxVww1y3K4CvA95WAHdQ8xWHDwJY4b1/tlwupwNDVVTKQ9rfP6j19h3dsv+Ow29bdEWvUmO0CWBshowJCTZL3kQAW1pPTb1noPTK9oG0no7Cp9b/7LWi+6YAXP8zuMnn4rFG4kfnQ3MYgIgIU5jxDCmKCigBpE1xZlEfvPDSErffrFkU7BNQpSutxQ1PLo6zSerFi9RV/CvMXFXVQ1R1H1VdhGaIbxnAzgQ5u4vtLsUx8yMA7mPmbQAOJKI2VV2XJMlLtVqtViqVaLBUlUqpn0vloTofOhBVMptzv1h4dd4Yn7cR1GSJwwhiQhIbIjUBthBwJoC8ElzvUHqzKL5+/+l4zQuGu9Kbyplw4m04Ix/xjI68+W6r2gZifdI1dFSaEEtdOW2AJYG6hnqXEMaOnL7ptGO/+L5kjVks2/JjM5nIZKJAoihLmUyIIAjIGANjTEBEHSIyWUQ6RWSdqm5V1YqIpC3RDImoQETjiGgKM5eIaKOIDKpq4r2Hcw6NRgO1egzvUq3V6l5Hxhuys9OPP7T0lke7tj41nQNiG0FtBmojeBMR2yzIRNhKQh9U6L6kkMGq/7t6Ii8uXoDfvRE2bzprx0n/hc93FLiQi8x1zYq0CdAHvcdkV4V3Dupi9b6OgosR+wRGvU3PPuXSHcXcPiMGnvAvcJIZlwsjG2UzMESUzWa16SExZGxLGFS9sVbFK5SUAGBYWYoIMzN5BbnUgSCaph5xXCfvvSZJouVaw1NWejrfL3NK1a07frHwmpFsXcgRvA3hTRahNeRsHmKaXpZtIDoa0P0AoBb7SwZqEt+/AP/6ZnD5g/LGnHwbvtlZCAYzAYbzJwwo4U5xOl0aUB8jcDHUxUSuoQ4pJE0gmbCt9vFTLm4UM2NHDCxNlidDweiQOAyCUDkwFLBBEFhSZrVEqkDzHLEVAiA6PFBFE0pFkjhS9YjjVJ1Lkfg0sZ3SO+rI8NBSo7vvznuuz8S+lDMhwBbWhmRtVr3JgmwAmAhqAlolij+h5svfqMW4ZKiaFu49F1e/WUz+4MxFJ92GS3MR246M+bYSGEAizD8mJ4d6p+oa8L4OcQnUJzA+hhWnqU+gUdA2cPKxnylNHj/rmOrW9N7+F5JGOiQjyXIYcgC2zRejiVXFw5Np5Y3xMGxgxBMJPMSlFHtPUI1NG/eNmhNm8uODUzZse+nB+x78WVs9KXXaDMgYspyBNyG8iQATwIRZwIawYPOCQj4LICSFDNX9V6qJ5O5bgH/8Q/D4o3JnnfhzfC6yvM/IdvPXADpaLd0KoaJPNS+xmjSF1QYkTeEkVfYpGR8j9Q5WRKvjRkztPf5DC3j0iCkn+AQvlDdUu6rbXaPWn5KrCEEErTwXTTKALbDmRgSaGxNk26bmppoQc7p7ux546PE7ZHvfutHGUJ4DOGMRmEi9sSQcwgYR2GTgOCRvDFXVaJUU81sA9PcM+X92Trru+yT+8w/F4o/O3nbyrTiaGF8cUwgOIMZRreZegerDgB6YJiQSw0uqgYsh3sFrjMB5eE1gfAovHka9pjaM+ke2TxiaNnWujBkzOcxnO/KFXKHNBpnRAODSRm+lVh6q1odqPT0bkjXrnuW+oS3tLo1HsKGADIQDsAnhjEFAFgmHsDYCmYBSG4BMRgMQvQTQcYBOBwBVPN5TStd6hxvuPx9L/xgc3lL6u5N+hpGwuHl0u33a2N/nDiTSXxBIRHWCNMilMdQ7DSVF6h1YUxXvyKhD6h0CCKCCVLxa9YASKYlyK/AOIJAyCUFBDGImB4KlEEoMbywCCtQbQ8QhxFiEJqDYWLDJakBEm4g1UKFPDI/Rq16xY9AdZQzOXzgf/X8sBm85AeM5t8P0eXwtItYRbfZToOavCyDxKj81RCPgaKJ3iL1TAw9xCVgdvHcw6uBVm/pNvQIKpwJV2pkKBQCEFKoMYoKFITVGQQxPBsZYeLIwNoQQw3BAjiNEzNioQKzAebQzkJRW9lXcbXEqctx5uOryYUv1R9LblkP1+JsxjS1+MDJn7wkDuhKEHACQQqD4OUgExJPFq/EpqTglcXDqEXoPJYETDwbgROBVAQY7ABCIJQKYYQBYZogaWGMAMkhhEJiQPLMaG5BTlvWUsgXjvJahAxS1RqpfH6i5eYjxhfs/i7clj+rbm8VXQSf/HB8T4LOj2uwzgaF/0GZ2oeHuVqjq48zIQzHee4QiSLUZgwN4kDYdt0Kkqq38BM1XhYnAMMwKGDQ979y0rERIRbENQJWIPgDorF0m2Ei9Xt0/5N4njH+//zzc9XamRH5H0iAffiOC9gLOVeD8kXl7bxjyxYC+OqMv0VaoPsCEukAigNqg1EEEFlWBQKHUFC9SBoOYiEUhRDoIaInBiSgyBDpJoeN2m9qG2Mv1/SV3iir+s1zFbc9chLc97vgdzWR+uYIfugUnC/C3keUlHQXTaQiX7LUCox9en1XwIBENCqTcvM1FVe0gSAcMzYVgxN6a8IrrBit+IHFyrCF850Orcf/ll781Pfd69K7l0j/mJxhtLb4+ot2uDy3t1T30Vihxeml/2U1WxpVLPol3PA088O7/MwI6/ib819j2YDOb154vvBVSxfXdA+nEBz6Ns4G3T8e9Eb3mUOkdJsW++NT2UjpHVO/V5vrvrRfVh7f3pTNLdZyLdxE84N0HEEtOgMsRzukdcBUV2vRWwYOnbTuG3HZXw4J3wki8Eb2uQ/WdojW/RLz/n+CluKaZTMhzm4eJwB9aFHADFf1X7+X6h/4MG9+LubzrHDhM934KLyhoaSPB3/yx3Nco42+811UPfBbvWvD67vSu/0eb3enEn/K17RkeNExXvPHTvyfxeuVQQ0be9zn50hs//c7Re8aBw3T/Z+TScl3niuBm9cCbLLeXGjr3mA3yl+/1+N9zAEHQ6oA/rxLLBPF49o1Fl54vxVJ08Ge/kwvkN0vvPYAAHv8K6ur8BbVEnlNF6XUArNQS/ziJv2jJ5/Cm07W/k/SeWOE9UddvUJ5+pimpYhODTtyT1Y29fsOrv2fxhXj+vR3t7+l/BQcO0z2fc0ucEyeil+7OfV7xFYXI4gvx4Hs9zl3pPbfCeyA67cfmFiaziVX/BgCUcL1XGf27z/vz8S7vNN6I3t23oN8caW0//+lcF/0PC+4VIBJgZm2aPw3/y8AD/peJ8DAtOQEuZLfAQ0sK7Q0rbv6SE/Yen/L/017ojH8LZ5/xb+Hs93ocr0f/D6s769KBP+5xAAAAAElFTkSuQmCC\",\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic3bx5uF1Flff/WVV77zPeIQMJIYQxYRRBpBGcQFEEbVQQUXB6xW5tWx9+Cm07IYIitiJog2P7qu3UCN22aDs0KIIyg0CYyUhCyHiTmzucce+qtd4/zrkhQIIogz6/9Tz1nHP22buG715D1VpVS/gLktnZjg3P2wGz3RC/N9hBCHtjMgOxGjDZv3UAkyZim4EHQO4i2j3UkxXUb9kkcrb+pcYgz3aDNvLjOah7BSZvRnwLX/8D2axILM0Dtx9ODgGGt/P4GNgtqD6A764i3+iJ44dC9CD/jaRXyqzXrHs2x/OsAGhrL9sB8W/B7ARKwz/H7TAE2btAZj89DbAW6X4HHRknnzgW7KdU5fsyeMKmp6X+J6BnDEAzhLWXHYz4c3GlG8l2HgL3frDsmWqzR5KDfpnOykkIL8D4OHPecIcI9oy09kxUaut//CKCfp7qtMuwwb8DnrOd5nOcXIfJCryAOgEpASUwh5HiBMwKEAW6YF1chIghthtqL97uSxG5C8a/TXvsBLx9VGa/8Yane6xPK4C2/kd7EuWblIZ+itU+BMx93E1OFmLchqQpTmaDA0kAlyDSwSwizkAFfN84RAfOQASLCVACDVgAESOGDZjmSDwEtYO20bVVaPMCionjiPoe2eXNy56uMT8tAJp9I2X10GfxyQTJ4GtADn3UDd6NYv5niKtgyQxcYjinkCSYi3gHikeSLhDwXjHzTNlWB4hEYnRAgoUSmIIqxAQsYEFQA/JRNHZw+lqiTn90R/VGYuNKQl5j/cTH5JD3FE917E8ZQFv23b0oJf9GNnQd8PFH1y7rkORKLJ2BTxJcAqQOSQyXGEiC+IB4wZxHXMABeIeZQ3q/MBQRhdiDNGqCaMSiYTFBKIiF64FYKBbAigKLD6PFsYjt+uhOcwHdiUMRe5fMe8uSpzL+pwSgrfje+/CyK1n1dcBeW/7wMoZll4Kfhy95SARXMsSDSxxkIInifIK4gHpH6kAlggjOOwTBJEFV8FIQDcQCGIh6ighOFdMELQKYYF1Bg0KgB2ZuxG4kFqvw+cmoDG7V/cXk7Z9iulx2efvX/1wM/iwA7bLLPIe1v4m4RSTJuWDJI/+675OUB3ClCmSC9yA1cKn1dF3mSFLDRJEsAYk9wJxSTEzQGW3TXlEQC6G7sde/0gzDZ0Zlt5Ty9Arp4GBfnBWCgxghOkIhkBsxGK4QYgs0gHZAQxPtNLH41q2GH4jhNFRfwrzK20ROis84gLbkohLp4C/IuAXso1v+UFmLlK4gLc/Bl4AMfEWQDHzZIAFJhKQMLgWzhMayjTz0kyYbrt2T2Nq3a5WFE3HWqgYzNxeU81ao5ADVpJ2ldLI6G6YN+o3zStI+CF+9n1kvWcYub6hR330mIgEtIHSAYFgOVkDREegYmoO2QfOHCJ3X4thqDirn0rUX0Kr9rex/Uv6MAWhLLiqRDPwPafdBxN79SC3yS1y9S5JVoQpSEnylB5wrgSvTAzCt0Vqzmfs/32By8cs2xZ2vXGJHjo/KnlVz1aEsLZsXKVQkpIlXTHo6T8wFjU5iTELULFpEQmN8Gsub87lq2gy/5pUM7ftb9jtjgNJO07DQQHPBerMeYqsnztaGmBvabhNbVYivemRwfJWitADktbL7OztPO4C25KISvnolWWMN8OZHasj+L5Luih9QfAWSmvVEtwquAi4DyWay6aYHuO/8A1phYOkd9sbVTbdgVlYqJVk5wycpWZaRJY7E+2i44L2Y0Zv8CkgMCMQ0xOCKGAndnCJG8m5ueacba7pkw/Pksp2rvrkH+3/kXqY9fx+cbiA0HbEDdIzYBmvRE+12l7y1GRffsRUj/JBubR6xdbQsOK37tAFol13mOXjzzymNrQL+/pGnS1/FZXvg64IfAKkqSTnBVRRXEaQ8g7HFK7jnU/NHde7tC5N3RpKB4WqpKuVq2cpZSpJlkvrMSqVEvE8ty9JClSJJJIr44BwWY0xjNC9iWZ4HH2OUdrsjzpm1Wi3X6RTW7XZpdNviwsToQfodP92tPpj9z1nG8Pxd0M4mYtugEygaGdpWQgO05aCxFI3/+Mhg5WsUQ3vx0Npj5GVnh6cHwCVfv4x0ZAViH9py0WcXIpUDcPVIOiBIFZIauKrgKg6z2Sw8c0m72XK3uA+MuMq06dVqzSqlTGq1uqVp6iuVsqRpGtIsM++ceO8NEQQi0AGmuKAElAEfYxTAQowUeZBu0U3zTkc7nVzzvGOtVpdGqyHa3rTpUPvSjpVyreDgc/dGZB3aVrRlFE3QlmBtoxhXtPUQlr/nEVTceRQzd5c9/+GUpwygLf7Ke0jHykjrS1suavpV0vqeuDqkdUEGlKTsSQYUqcxmcvky7v38c+6yt/xqvHTwvEp90OqVTKrVitVqNcrVasiyTBLnUhEBGAXW9ssqYD2QA1MT3bQP4g7APGBOv0w3M4kxxm5RxG67nUxOTkq7ndPO29YYb9pQ55a1z3U/Opb9P3wXA7vtgbbXow1HbBk6aYSGoA2hmFgK+ggnxoEPYENR5r/3y382gHb/xQeQFm/Gr/0ImOuD9zXS6p4kg4ofBKkJyYD1gCzty9IfXlVsumuXm7NPrC6Xh6sDA1XJyhWmDQ1ampa0XM689z4FNgP3A0uBdr8vSk/veXpceFj/9y39/6ccAq7/vQLsCewHDMUYQ7fbtWaz6VqtXJutCWt3OtJubBo7rPjMXsmMA5cz/60vJ3TuJzQEm1TiREJsRsKEElqrcEWfE0UJcz4P2Q9kwfvv/ZMBtD98I6XW+QXZkj0Q9uzdLZcgA8OkdYdMF5KakgwK1AWfPof7Lr52vJk27qufVq0PDKTltOoGBqo2OFi3crmszrkB4CHgAXpc5vpgSf/7MFAD9gVe0AcHYAlwK3Af0AQm+gDrVmV2H8i5ZtZpt9s2MdGwRqNJq9WUVqsZ9m1f1BqqxAr7v++laH43sWHEhhAaRhjzMBkJExNgJ/XhWUK+YDVx9FWy/9nbnN4k27oIQK39FUqLFmLhlX1beB+U67jMIRlIGiF1kApen8PCzy0cYZ91Dw2/dadp9ZqrVWtFrVZLa7UyWZaVRGQc+D2wiR73zARKqhqccwqIquKcmzSz14rImUC135uWmZ0nIrf0fw+oqjjnhJ54d4AGPU6dJSL7VqvVoSRJOlmWSKmU+KxSssVjH6zOa/5g8453nn8bzz3tEHzpDrTrECeQKnjBJSmhdQ+izwEWkNx/Oez9ReB924Jpmxxo91+wl0rjjc4vO7d3wQKu8kP84CyyIUHqgh82/ICQVA7k3m9evybstXb98FtnD9Xrrj5Qp5RlWq/Xnfd+AFgILANSVfVAHZjVf4E1EZlhZs8VEWdm3xCRD/QBfqSjIhtU9SIR+XszUxG5T0Q2quokPV25EZjsv4wA7AI838wajUaDZrujk+NjyWSzyZzJ/3pwTnrffPb5u79B2wsJEylxUonjkTAhxPENaOcURBIADfM/6bT+H7L/6Uv/KIBmiN1z/tWS3TqESM81JMlXSQb3QIYgGwQ/CH5QoDaflT+7cXNjYGLl4Lt3qA/W3WC9rtVqxdfr9QxIVPVeYKNzzoCOqjpVLSdJUg0huCRJusC4qp5FT7wPAlYCP1XVkf5zs4DXAbsCtwN7OOfO7nNiRk+EWzHGwntvzrlSn0N3APYzszjZbE50Wu1sfGKcZqNtu05+ffO0aitlj+NeSphcTGyATkCcgDhmhInlWJziutst/E1D9v2nIx/rmH08gPd+7ijSpc/BRnpW1+RWXGUd6WCGH+5xXjJo+MFhRpcu6q6+a2jJzHO65UpdBgeqbmBgwMrlciYiqqqLnXOFqk7vc4WPMRpQTZJkB1U9FEhF5Fwzu9DMbnfO/VBEXqyqrwGmHKW5c+4XZnatqr5dRA7y3p+uqh8DVFVvE5H1QAtwIhLo6dSNzrkKsEeMMQ0h5GNjY9rpFH5iYizutemTrjTvuS0G91iANcYJE544HoljQpyMxOZcsAN7SM3+AHHPhbLvP/9ua7zc47jP7OPEhz+KdcA64MIdSJKBBxFFpPcGigmx1Tc/f9G0syZrtZofHKi5en3AyuVy0gfveufc5qIo6mZWAWaZ2Rzvfdl7/3AI4SozGzCztqqeG0L4ELCPql4QYzzezFRVH1DVB8xMY4zHq+qFwHwzOyOEcF6Msamqg865K2KMK0XE05vaTDOzUgihqqojqnqD9z5kWZYMDAwmpVJGvT4gS6af1baHbzyY0FQwD67nzBVngMNz4xYcbOXHLMRzzEy2CyB3nfdicQ/8FOvMRrsQu78A2xWJYCaY6zGwxf1Y+quwbNrp19QHB6u1Wo16vUalUk5EZGdVXaiqQ3meO+/9BhFZrqqr6OnAE83sH/ttV4HvAB3n3Plmttg5d6Zz7sNm9i0zu69fvqWqH3bOnWlmy83sAhFpiMh/0JtgO+/9e1X1TTHGATNbb2YPOefGVbUEDKvqQmBOqZS5wcE6lXpdqgODlWXTP/Iblv48RePeOOt5wrUvpZrvDt3/7WMxS9zi/+aezx2+NWSPssImeqbY4j23XJDSeszvBAJODFHBWcrIA1c1sr1zN7DHjqVKhUqlQqlUcsA8M3tQVV8MNEVkjqoGEVkLPKCqVwEvA3Iz+yDwG+BMEfmtmV0hIifHGM81e3T8Z+p3jBHgTu/9h4qiOM4591ERuTKEcIb0JCMTkSuAGWa2v3Nujpk5MxsFEhFZ7ZybWyqVHq6pOrQaJuPOcxvNve6sjy2+l+Gdd8EkIAJ9LFHWYFMLokXvN9vzQWCLE2ILgPbA53bS7qrfi3WP7l+6GvxcJPRG4Kwn5LE1l/FVu63e4fM31CsV6pWKZVlm3vshVb0S2BBjTAG890PAAar6ahE5EjjPzOohhLO89xeaWQ6caWZnAS/vA3Wlqv5eRFqPAbEmIkeIyCtCCAeKSEdEPqaqfw/MVdXTReRCEXHAe4B6COEqEbk7y7LNIQRCCEWaprO894eWsmyTxuhDCG7NzH8s77X+jBcyML2AsBIxQ0xwKgTdCcl/h9kRwAJh/fds4blz5aAzVz+aA7vtE527fi7WXz87/wCwO+ZAVIgFuODZuOqmkfrrJirV+k5ZkkiWZWRZtqOZbYgxHglUnXOJiKwMIdyRZdnVIYTXmdl6EXm7qq52zn1BRD6gqv8CnAtc65z7sarua2avF5GjeQyJCH3R/IaZLXLOvSHGeB498f+AmV2oqqu89/8nxjgmIrPSNL0qhDAjhPBiM9sdiCGEpvd+JE3TOTHGDZVyOSpUNtVe/fMZI9cNMn32LliMmBnmIs4ghnshHtHrybU7Iq9/A3DRFgDNEL1l/U6uUhzRN8wbUD+vF8PAepecoHEandburbkvv7mSpZTLFSuXywnQCSFc1xezIefcc83sOOCQoig+18fgy2Z2gZl92cyON7MvAb9wzl2vqqfHGKfW2rmqLnTOPaiqK1XVJUkyD9iD3grlPX0wNwIfU9WXmNmXzGyVmf1cRN7rnDtdVS+MMTpVfTcwA/gVsFBExsyscM4dVy6XnRmxiGqTw6/cYcbqKw9nmo6CbEREURFIDPW7IGETyAwIL9PO+oZZ7516gLOP/budTZfuIXp3FT89Q9yvcaUhpNTzKLuy4TJlcmLZWPqi+2P9wIFqtUq5XDLv/d5mdqeqntLXQaNm9gBwrIisMbN5fZ10sHPuJ8C7gbu9919X1XeZ2dH0ph8Xq+p/A8tFZJr1RObFIvICM9vVzB4Efq6ql5rZXSLyfOBvRWRXVf2EiMxxzh3vnPt2jPEdgJjZcF+kZznnvuGcK6vqwar6ehG5XUSeZ6YbBcOMxIrx20v5is2UXA0NPYesRgfqIf4Bs5l0H/yDWHUZq45eec63/jDpALTg1c7dNouox9Nafh1KgKRnrhWPakKINZrtlzSnv7ZWq5UlTb1kWVYG1hZFsczMFpnZ61X1VBFJrfeKvm1mL+nruLkhhKPN7MNmdngI4Twzu8Y59wHgWjP7sIhcaGbvV9WXqGpZVVv9UlXVl6rqaX0996GpZ/v68jwze4GZfTiE8BpgjpmdZWYvCSF818wwszSE8E4zO9HMVqnqMhFZm2VZ4n0qWVay1ow31Gg0DydaBTMH3qHiEGeoy2kuv4YY3wy3zUL1WOjLq133ritxP3w+2HSgQTrwc8p7DeBqDl/ueVxi1o7Nimza5VNFqVqlkmWSpulBqvrrT3/603bTTTed6pwrPVZ3/TWRqnZf/epX3/ye97znZzHGwVKpNEtEXhVCuL3b7dLpdGzmio9XZKBb4PIKoQXSNEKrS3dJh2LytfRiFqMWTvmDe+m3X5WYne30+kUbnFkvCC38L0U+HdZ2KO9uSMxw0Wh3xyanvXHCe79TImLee8ys1O125998881HOec46aSTfrd06dIlCxYsWHDvvfcu2n///fdutVqNPM8LYNqvf/3rI733d5xwwgnjU4MaGRnZuHHjxk2zZ8/eYfr06dMvvfTS/VV12pve9KbrZWrSvhWJCHfeeWdz8eLFr5kxY8YtL3/5y1t9cOyBBx5YMn/+/N2yLMtGR0c3XXHFFUclSTI8MDBw1THHHON/+ctf2hVXXPGyer1+/ymnnHJkURSrsiwrpWlqeZ6Lc07Gh49bOty4ZJB6UcXFnh+gvcbQfAbGlcDrwaabdcfMznYJt66Yha2+A3hLr4tuBGQIbWe0V7Yp7xlJY5mQPjfUD16YJok453DOzVTVmycnJ1/kvXdFUXROOumkF8cYJ0XkkBNPPPEgM/secBpwu4hc8etf//rI4447bvyEE07YDNwAvA04cqt535L/+Z//WTk5OZmedNJJP6PnsgJIY4xVYHfgqGOPPbZ26qmn8sY3vjE/4ogjqsB/xhhf6r1/N4D3/lxVPfG6667b0O12hy+++OJ9yuXywAknnHD9qaeeuujHP/7x604++eQlIvJKVf2ZiMzy3m/IshJh2iE1Ri/dn8I2o/lGOg8NQLeKCuDWYr04l0tX38rNuoOjU+zpdHHSW2EAKiWE0PO2FTW6K0qE8fWmyXBWqdfTNLM0TUVV91fVDVtzhqp+xjl3HHC+mVXN7FQz+5CZHaSqHwVYt27dGjN7jZmdr6r7hBC+r6qnq+q5ZrYsy7LEOSchhAtCCF/ql/PN7BwzO8HM/tBut7/Sr2uVqh5iZuc7514FnA98N8Z4ppnNz/M8AmRZNg04X0SOPeWUU64WkTkrVqy4sq8bVwP7eO/FewdpdQjxMwgTG2g9tAMxr6BqGBGTdAtO4QFH7ua7qLoXrjHvEQBtGmopph6LghZCc023M/yCr5mZgk2tCBpm1th61aCqJ5vZ9WZ2DvAZoGlm58cY/11V/y/ATjvtNBe4S1VPB74FvBG4EDhTVY9xzomqmpn9j6r+SFV/FGP8jZnd1Tcmx1er1dMAhoaGZqvqN/ov4D5V/ZCqvkNVvxljvDTLMm9mOOcuNLNPm9mNr3zlK1+oqvHKK698oZmpmY2LyIRzzkTEvEinW33ORbTXdqEbUQUjwUiINn0LTtaYi9meiWg8ACkO6GPQQaRCtBwfCyIlEEOHO6jf1bmkSJIkAENmtjaE8KrR0dHvAh/pc+FewMMxxt+IyDkicq2q/peIvK//tlm+fPnyGOMxwIV9Sz1mZpc75xYCRbPZfDO9KcjuZlYDMLMNZrZSRH6rqqsnJiYAzldVAd7br2d1COHMNE33VtW/FxFijIv6n2c6537rnFNVPRxYd9ddd80xs/NDCMc659aratk5twFI1dUXEJM2lnchRlwUMI+TKpCjZEjYT0PsJBJ1fxwHA2ByD6KG8wENAWcZBYKUM4b2ayeJK8eolqZJbma5qh5YrVbX98FLb7jhhi8fcsghpyZJsjbG+Enn3Dn9acyXVRURef+ee+65B70A0b/EGDc5514A/G0I4c0A1Wr1rna7japuvadwd9VHtkEPDAxM9EV4tYicEULY0Xv/9yJyboyRGOMX77vvPpfn+SnOObrd7qdKpdJbzGxP4JMzZsw4ft26dTNijEc65w4ErnbOdfO8GEqSxJLpB25ktFzDaUSDoNERDEQdjvsxDgQ7VFRDglgZo95TZPogJlUsRpCIRkEAqQ672ryuiQQRSVV1DzObEJH/k2XZJ/uK21988cXv74vyHqr6MTMbT9O0VSqVjqHn9OTyyy/fddWqVfckSXJ4lmU2PDxMjPFmVV3TbDZHNm3a9Gag+pOf/OSHSZL4iYmJep7n3YmJCdm8eXPsdDph06ZNOwMvufLKK1/5+9///tA8z2tFUQB0RCTz3n8QwLmesynP83enaTrovf+AmV04f/7862666aY9RWSWiLwjxniqiOyRJH5pURQastkxteowRW6g1tsVZgZiRHsIOBBjEI2VBNXe3kUAtSaQoma4QsEJFoQ0rbq0hjmX9yTKhoHRWq32yRUrVnyn2Wx+qlqt0g9R4pyT/pywBAx1u48E+WOMu91yyy27sR1Kkt7y/PLLL3/L9u6ZIhGZ3e12Z2/93LZo2bJl//2c5zxnLvAl4L4sy+7tdDoHxxg/MzAw8KlOp7PUzIaT3to+NwYMyUpYXiBqRAOHEdWDTiJTLkHFoYVsUYxCCwgQlRiFEAQtDEmHVBLnvS9UNdCLV7SA3efOnfuqkZER1qxZQ6PR2OJ6+muiJEkOFZHXmdmFIvK5I488UkZGRkoDAwOvA3YVkWY/LlOYmSVpDciGevtrQi/Or7FvPGg/YnCDc72NnvRKdEqkidDEaKK2DmMN4hLvk2az2eyISINe7GIDgPd+N4CiKNi4cSMPP/wwo6Oj9EXqr4IWLVp0D/B3RVG8Kc/z7+y9995Lgc7atWt9/5YNwKoYY8PMmnnezXGuRKBFpAk0UBqYTqDoFrxMSTDskTCJ1VCGCQgmZg4vZoZnMoa8UqkMls0siTHuY2YPbauzMUYmJiaYmJggyzJqtRq1Wu0JReyZoKIoaLVaNJtNfvCDH5RGRkZeOmfOnN/ssMMOyxcsWPBGEVl37bXXPnDyySc/L8Y4R0T2EZGFIhLE2ySiE5jMwBCi9QL+Ig7byotvWALxkXi/yRCQRMU5jFhYCXGaxDgeuk2DctL39TXpBcCfkPI8J89zNm/eTJqmU55rSqXS0w5oCIH+epZOp/MoCdiwYcPJ3//+9x/3zNe//vWFJ598MmY2ADRU1RVF4V0+TmahEYxpBBVBAog6ByJWe4ThIglqG3CyCmwepkNmKIZEwUV1DlTF8gZx3GBGGmN0fZ3x+B34j9Bm59xD9BjdqequRVEMbz2oJElI05QkSciyjCRJcM6RJAkissWCAqgqU/NIVSWEQFEU9L3M5Hk+NbnfFq1yzo1OratjjPvTC8azadOmV/bvmWNmDeecxBgTjZMSi9CIQYcR5zykeFUiINQQAZEHzeLaxDTeLUYKzEPcAWLcY6ZmipppjMFI8tEGzeXW9TtnWZYCrFfVA+jtBngUOefuEhEdHh5ePnPmTN2wYYMbHx8HWNV/BmDL4J9BUu/9LWaWzJ49e/nAwIB7+OGHa51OR60XtdsdyNevX39zrVY72Dl3dwghiTGaH1+UabGpFQszEg3OgSgizjnE9u8bkdscdqczC/ejyeL+Mm6WYQ3MopmoBefMJOk21laTxuKKmbrY83aPmlkSQrgeoF6v/wxARO4WkearXvWqHdI0PcE5d2KpVDrhqKOOmiEiLefcfc8kYluT9/7mUqk0/qIXvWh/7/1JaZqeOG3atGOPPfbYrohMAmumTZt23ZIlSxaaWaqqm83MVFVKnQdrne66ajRJXHSiEcQkGjaO0lvOkSxB7QHnE1lCHFyLWc+3H2l5xKtapqYuRpNue6ySFSsXhKCxv05tAHS73dWPEZ3k2GOPnT4yMjL3C1/4AqVSic9+9rOMjIzsfNRRRw3S24X1bJysXGlmpec973kvnT59euUTn/gE8+bN4/TTT+fee+89/MADD1zhnFvfaDRmttvtrK8eGj3VECzLVy0IjfGKRiOqOtRSU0vFaE3hRJi2nsKWJ2xuL9fa7Nc7t7HXtLNGjOwgaoWpYEoSY3emaPeAPG//CkoVEcmdc4QQ5l166aVXNxqNI5MkuQ6we++99yWHHXYYt912G7vvvjs33XQTCxYs4NZbb91XRK53zt1mZjOfcPhPkURk0+zZsx9cuXLlwcPDw6xcuZKhoSHuuusuDj30UFqt1jELFy5cVhTFXO990teteVEUxJi3he4+MXYjgDnUjAg4orWm9nJo2GGmm2bLEnnrzRP6k8MPe8QS41EwkwTFFIsaRIr25qt8vmY8uHlV770lSbIaOOKFL3zh/y5evPhKgOc+97nV733vexx++OEsXbqUiYkJ5s2bx2GHHcbvfvc7jj322MV33nnnI6HUp2nSLfL4PVJHH3307BtuuIHjjz+eK664gvHxcV7xilcwOTnJ9ddfnx1wwAE3NZtNt+uuu74GeKgoCosxGq1VY3lr9CoN7CjO1KI4ExEUxZNN4SSUXiwvu+YT/bCbbRLldoSDMTnSO1seogU1cTEXb2YyvvaOscHB31dG0zdrjFG893cDx+yyyy4bP/OZz5yqqqgqt9xyCz/72c94xzveQQiBgw46iO9973ssWLCA973vfe+cum/Kom5tXacAfeznFEBbfzrnEJFHfe87erdY8F/96lf86Ec/4rTTTuOaa66h0WhwzTXXcPDBB/O2t73tnd1u99uqOlNVfwVYu92VOe3rapMjCyei2lwfxXDOnMTgRQSTl4OB8QczVkJvcyPnvGnuJDI+ihWvAKaJ2kIzqmoiqhBUpNMZr8/ace8j1snzljrnvHMud87tF2Ospmk6bGZOVVmwYAGXXHIJeZ6zdOlS1q9fzx133MEZZ5xBrVZ7FHjbA3Lr348t2+Pex3KhiDBnzhyuuOIKGo0Gq1atYs2aNaxfv54PV+O33AAAECZJREFUfehDJEkSut1uDZihqre3Wm2X5+3unPy3x2548Kpu6sV7QROPpIL3XkYxDu8teev/Kjrjl+dctnpF71W1uFnjzvVHnIV+rSBCRDDBDDWl3GmM/LrUWTbS6XQkxqiqehuwT7fb/Y+pAe68885cfPHFpGmKc45SqcQFF1zAnDlzHgfSE5W+W2pLeTLPPBbsww47jLPOOot2u02e5+y1115cdNFFZFlGv8/7qOqt3W5Xut3cyvmDGzutkSs0UlLFMHEoiIlhbJjCR8PcIWLj1p4o90kvPegaSe/bC2wOcLsZY50CaRdYNzfJI6gbWL3LIe+euyh9+4ZSqSKDg3UnIieq6n3lcnm3vsf4cQP+YwA8lgufSISfSGwfW7z32/s93ul0NojIfFX9z0ajRbPZtP35wZyVt/zbKomTcyspVkqFSoaWUkSEGcCBmKy2uN9id9LCl8NWu7NU9UKsdHEf5YMFNgjgpLcBFpCiPbkTYbKgvXp9nnes3W6rmd0I7Nduty/dlsg9FpjtgbctDvxjL2B79W2v7anS6XQuN7MFwPV5nlur1RLXfXi9FRPtojM5B3D9bXwighNYh3Fgb65culgtfmEKty0A+qHWFZrvNG/LPEddI3WGiLkE8JiKt/TB2340viD9/X7tdtva7bZ18/xhM5swszfGGK/bnu7a3oC2J7pP9P2JxPaJ9KeZEUL4dYzxFBEZy/N89cTEpO902rpP6boDlt98adNjPsE0wSQRIxEDle4ULhp3nu/Xt696HIDy6qVd1Asql/ZMdXy7F5ssiUURvDcRr1i3NT5DWxsmKvnitZONhms1m1oUxdVmVu92u0NmNj4lftsb2JPVgU9WBTwWzG2B2O/ThjzPZ5tZmuf5NZONhmu22jpkS9fE9sho0R4fRhDvRRMxSxLDY2OIvq0nmXIJKm05bWn3cQACOHFna5hzX1+MM8ytS5yId+AEBMErsui671b3Gbjn2G6n02w0GrRarY6ZXQUc0Ol0rrZetOsJOWFbYG5Ld/4xffpk2zGzTp7nd5rZc4HfdDqdvNloWrc12dqrfs+rF1373YokvU2ECeC9+FTEsGQjPbcfxLlLXJJ/+lGYPcr0n3LPerS8D/DbHhfaWxOxsVKCeYdkHhMvRAvDS2/58Y0H1X9fGZ9o0Gw26Xa7m+htAH99nuc/2NoIbP35ZET6sRZ4ayCfTB3barvb7f48xvhK4A+NRmt0YmLSJpsNe/70m+tLbrrsRrUwLe0fB08F6Z2rtzGI7+jpPq6MoTRfTlo6sl0AATq+/U+az76h/1AVlZg6o5xg3uNSj6WefHz9kj1orrCdSsvWTUxMyOjoZtrt9lLgTjN7ewjhB8CfxYl/zpTlCUpeFMUlZnYicHur1Vo+OTnpGo0GOyVLVkvzIR1bt3yPzBNTJ5Y5LHGQelPE5T1JBHTObb7onvFYvB4HYO3kVWuIpRSTb/aXLSd6WJQ6c5nHSg4p9xqS+67+9tCe9QcPk+66NZOTEzI6Okqz1VpsZjer6luLovjZ1jrxyXLlE80Dnwy3TX0C62KMv1PVk4GbGo32srGxMRkd22x0143sOfTQYXf+5t/qpQQyJ5qmWOKQLDHxxiLM3tTXfV/TIknlnSselxXpcQACuEp+Tsx3HERp9Pz/7kWZp1tySEkg8bjUiROscsvln1v7kl2Wvrzb2LhhbGxSxsfGtNlsPqSqV5jZ60IIK1X1uq3r/1PB/BNBm6Lr8zzfqKqvUNX/nZxsPjw2ttmNj08Smps2vnju4iNv+cnn1qVi1VRESg5KhpQTXObIUXdEP/bRiPnsHZzaJ7aJ1bYuykkPt73xbbR+Zu8N2P6ibqycQrmMlZ1ZKYVyIi6VOHzzjz9/99ELlh8dWhvXjI6OsmnTJhsbG5sIIfwXsIOqHhRj/Da9I1mPom0BsD0An+iZrWg8hPDdEMLzgel5nv98fHx8cnRs1MbHN2unuWHkmL0ffMXNl3/+LtEwVErFlRJcmpiVykgpRcXcJrB9eqJbP9OL/5q8c8U2T7E/4WnN8J2df+iTtQKc3If7KyGyf7ONNbqUOoXQbFtoBaJKZc3hJ33igF89sOPVOcNzhoYGQpqWy/V6RUul8qCZHqGqS4CFMcZTVHvO2a0t67asLvC41cTUiuIxn+qc+w/ghc65nUTkd3mej7dardhqtbLJZlMzHXv41c/Z8MqbL/nMIrHG9EqCr1TEVVOjVibUM0g89wFTx14viWHHkLxz9du3h5Hf3h8A57x++i9jrLzV+ZZgzACe6+B3HqYhaIw4J+JMkbwIQyvuvHryZS9//i6tXB9YuSFMC0Xs5W2KoeVElgCY2dFmttjMfk7v8M1g//qWds1sm56XKRAfc20N8J/0gvgvBO4piuKOZrMZx8YmmZycYPPmUXYb3LT+pXtu+ptrf/iJEbHujEpKUstEaplRKxNrKaTCCoR3AB6RJTGfPekle/s5Px3bbuzhjx64bn9tx92yrPigS8b+AcgQNqP8ohuZ28zxrQ7SynHNDtIulE5wxaEn/PP6WJnDT24faJfSSlKtlsvV6oCVKxmlXgCpDOypqrur6m/NbF2Mcb6qvlh7Z+keJbZbr3+dc8E5d4OILPXe7ygiR3rvV5jZgzHGVp7ntNtt2p3cmq2m73ZbjeOfN1nz3TXx1h+fv2PJaVYtOStnSK2C1lJirUxeSlmPcQwwo7e9b+gifPlf5e1rthm+fdIAAoRvzXytSHcv51rn959aCdzcDcxsdPCtHNfuIO0ca+UaWwEGZu+16pDj3vc3Ny1Nfr1oXW1WuVz2pSyxUqki5XK2dSQuU9VhM9vFzKap6gozW2NmDVUt+qcvMxGpi8iOwK5JkkyIyEOqOm5mRVC1kOd0Ojndbod2u0On0427zypWHLlv53X3XfWD69ctv3V+NcPXMmeVBKplQqWEq5eQUsZalBfSOw2PhuqHTct3J+8e+dUfw+bJZ+345vR3kbTrkE8dR1iF8LsisGujQ2xFrNUmtrvUmwXdboHP1RUvPOmfNyYDO02//BbuGu9k8yqlMlk5w7uEUlYy55A0TcQliTkRw0xxHouxd2Cot3PT+kcbxEzEQIIG0SISo1qet6UoAt08aLvb1uGyrj/hMD0gTK7ZeP2PPj+zlGhazoiVBK1lZJUSRb2CVlMk9ayldzJ+DwBi9gG01pV3b3xS2Yz+pLwx8RvDn3RZdwzrgyhsxvhJMPZq52izLVmzwFq5SbdLaEeNndyZlOutw97wwU5anz39ZzeHO9dPMCvxaZp4j08z0iQlSz1Kz/XhxHdxRFR7ESvnPIqPUTPV6LwX63aDKLEXEy6ChVDkc4Z15G8Pyw4qJtZvvOm/v1ixTqNaTpRSySXVFF/NROslpJwY1RKWeBZjnIAw1BtP9gGKclXevfmzTxaTPzlzUfzawBnOhwSXn9dPDpZj9i1DDmp2oR0Iza5qJzhrFfhuR5NOQdENTpPKwNiBx5w6MXOXfY9YtiZcef097e7IhE2XLMlSvDjn8IngncfMgllvQ7JzIoqkGsRUC4kWpCiCodadPuw2vXi/cmXBTslRIyvvvfauX/37YNGdnFbNVDJHUi67WMmIlVSpJs5XMqRWwouzuzB5J5BhqMbkDGflivzD+JMG788CECB8tfZO8cVOzsd/4pF8pz9CGOjm1DoB1+yStgq1dk6RF851g/puTtE10iLSGNpx95EDjjrFTZu928taOXcvebizfMWabvfhTV3f6UI3qqC9o6WC0ywVyiXYeUYp7rZTWpq/c3WPWsYBm9c9ePU9v7lEx9Y/uEOaUMs8oZSQVTJXZF6tZ22dK2eESkYsJf2NU0I/LwKjhPSLEb8i+YfmD/5ULP7s7G321cphEXuv98XeiL2gf3kxwu8N269VENtdF9sFaadQ6/aSDaXdSMgLfKFoEUhiJCcpjw7OnDu+497P1xk77pqV6tNr5drAoE/THUSchLy7odOcnOg2Rpub1q3M1y26zU1sXD1E6ExPElLv0MzjspRQ8iSlhKKSkpRTJ6WUolZSygmZiNyH8VKmMs2Z3BhDtlyRf83e17r1z8HhKaW/m/jywIy65N+XJP4B9JGljsiPMTSiO3cCRTt32im01A3keeF8oap57nxhWsRA0lEwJQQlMcNCz502ldqk109BEwERJHEEcSQlB6knJN6lmdOYlpzLnMZKQpZlrltJ1ZVLpB63CiPF7PgtfTT3KYv+b0TKb5F/HN/852Lw1BMwXobX9dmZmJrL9K3Agv5fOSr/jmdGVJ2bF3Q76nxRqHZy52LUmCsuj06jqu8qgjmiEtTUmEqF0vumgDlx4h2Jd2qJgHcuJk592ROT1PlSopomzpW9xiwl896tQumAvZlH0gcs1sJd4oTAxnCenP3Udko8bTlU7SvMN/NfFW9XAJ9iKmVJL/vkDzEM0V0Ldb5bqObRuagaikBWmLMQCKAuGAFDowKO3gpASbwDBJcICeI08SSJU8kceZKSpGCl1EnqNWJuBYLD7C1bsmBCC+MTMcqrfIjvlQ+y/OkY99ObhNaQ+K8ch+OdPnG3KXwco7xVY/eqyY3iqRk6xyJZUFeEqC4oFOYExaKh9JzaPSMiGOLECw6HpKKWeMyLI/XqxVMIbq1Fmk7scIP9txphxymfiUGfD3zL/3/84ulMifzMpEH+Bmls8yaMU8y535rnNOnP8rdqeA3I1eKsbSolB4NRdFgMb0Y0wcR64mXSSzggggeCw40rTIizrqlUwF5msNOj+gArPVykhR6t8P27q1x2yHt42vcdP6OZzO1sXBjmKODDqvxeEjfN4ANP0JlRRG43GBdljN5OWDCrmWNYYAizgw2mP0EdXzJ0s1NeivDZZDNXP1U990T0rOXSty8wsyuchXMrTLjgmWhDjDNQ3a1kfEr+iY3PRBuPa/PZaGSKDKR9AZc47x6KulUuwqelbrnIqe5c+SdOFJ4+HffHaJse6WeKBKwyyVtDoQca/Eb7qbSfarHItVbovpUB3vxsggfPMoAAcjahW+KNVlhDlZVPGcDIWjFbF5U3yTNgJP7oeJ7tBqdo9F84wMOpivwjsmWS+6dSMLUvpsJ3Bz7CdpMkPpP0FwMQYPyznByUHXFy4Z9VgdrpzjE+7aN8+2nu2pOmvyiAAJvO44tmboNh5/1pT8qnPTpj+se3nRjx2aK/OIBmyKbP8FMzN6bY257MM+LkMjGtzQy89pmc4z0ZetaNyGNJBGtv4k2gczVy+5MwHHcRdVoROOkvDR78FQAIMO+LtIm8zYndr8bodqcrRkuwG73jXTudTeuP1/zM019chLemtWdzpCkvir2EZI8jBx9xCTfNOYvfbev/vwT9VXDgFM05m2sMgiinP477lNMd6F8TePBXxoHQW+6tOYsfFsrDpnyof/GiJGHmzp/mrc/2SuOP0bN7CvpJkICZ4+2rjF8G5RcmDDrHvjt7Xv3XBh78lYnwFMnZhOg5SRxF6hmhyUlyNs/o2dj/X9LKT7D/yo+y31+6H09E/w/wHJVcjfUH5AAAAABJRU5ErkJggg==\",\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHiczZ15vF1Fle9/a1Xtvc98780cEjJCAgkgiUwiIghCgqLIQyK2qI0D2g6PlmfbbaONCmo/habB4dF+tBX0KdC2PFGZB4GEgECYIQmZp5vc+Yx7qFrr/XHODSEkiDKuz6c+Z9+z9zlV9T2ratWwal3C6yh64YW8Y8Ex4431M4yhOQAtVMUBTOgRQRGEWvtBlJnRgGJABSthdIWHrIyI1l9y3339F154obxedaDXOsPGr2+anFL2TgXOJKZWEIYP5oslL0z7EtE8Zj4M0O49f5qGofKAF32GRTe1GnWTZOkR5DUi0muC0Nxaete7el/L+rwmALdde+34nOcPgei0ILK/j4rlLmbztyBMfkUyUGwT8f+ZNGojWeLeBchvjOR+Xvngqf2vyPe/iLxqABWg/p/+YqFR+WYQREsLXeUuMH8WQPhq5dmRVMRfUR8eqquTt7Din7rOOXsFAfpqZPaqABy88spjlPhfi8XytSbKfZxAB+3l0ZSZ7hXD6wkWCAggClURGWJSggUAUjivokRIoJpq6gkkyl5miOJYqNq9VO6xer3+UxfHp4P9l8Z+8pPLXum6vqIAhy+/fLYXXFksdd1go9wXQZjyggyJH1HDDyEIQ1iawMZAjAWTsWS55QHHbEREGQwPABAYZhLxzjDBIpOcQBx7BwhUvOtDkiXk/WGqcugeirbJxc1LGvXaqY5x7sTPf37NK1XnVwTgg1deGcwcHvkWOKpXuiqLiPjI3XIZJBv91lub59CORWBVAysmDKyQ8QgsQGSNsakaUhAYIAPqlE+hgHpRVeMB730IFcfOK8RbSVPHTghZCsn8IJI0hk/fA8WYXYuhovfVa8O3eudy69eWLzjsP87NXm7dXzbA6oXfnJNBflwaM+4uJrpgt6/fTlFwC+dyY7w1Fvk8KAwYHChHRsQGAVvrEBgSsGE2DtYATAwFE4MBQAUCgkBU4D3EewtRD3WK1FmkzsE7gstI00zQaoEynyFNNkucLCZg+q6lUpVLRoYGj1KWv53wla+sfjn1f1kA+750wblBYGcXunpOJcUBu3zrsIbBryhfnGaiyEghIoSRahiAcgEjyCkCqxwEFsY4BCHBEAnIIzAEsGEGRDVgYgXUiQAMcfAeEDXwqshSFe8t0syxcyRZTIgz0TSDacYkaapoNb2kySaK07MAVEaLqIRnGkNDv3ferR7/rxdd+ZoC1Asv5L6R+k9yudJTuXz+YgA7O3EOwquQjyoo5POI8oRCBC7m1YcRKIgIUUgcRSqhVUSRARtvrGEPkiRuVBsDw83B3m3Ot2KqDQ8TAJR7utXkcjpm4qSgOK4nn88XK1BlOC8iziBOPWeOkCTkk0SROqU0Jm00QEkKtFqqzVZLG406vHxol6q4pNn6XBw3jh23Zf3ZdN11/lUHuPpzn4t6Mr2h3DX2T8T85eeoYjuKuT9QobwPFfPQYp4oX4Tmc0AxD+RyanIBxIZk8hE8sx3cuLnv4ZtubD774MOz01bzQI4KjwTdXRt57NhhDYO00FXOAKA5UgsozUIZGOjOhkemSdI8NMwXnt7vsIVrDl20uDhu2tRxRtT5OCZOUvFJqhTHhFYMbbSIkpai3oSvN0Ct1lY0mqeAMHFn0UUuqo0MHDkU0Kn7X3FF8qoBXL34c1HXxNYNlZ5xawj0qZ03DN3I5UqMYqFgSiX4UhEo5IkKBUUhDxTy4FweEobF4R19g7f+6D8a29etPz6cPPGWniOOHM5Nn1qKyuUKk+UgCMSwigoLMwQARNr9ocucEUC9TzWu1WqNDRvrw8sf6HHbd7xz0uxZd5z0iY+VK+Mm9HCa1aXZJG01iZJYfbVJHDfV1BvwtQbQbDSlVsvB6+JdQHxvZLDvwDq5d8/86U/jVxygfu5zUV//4I1dXeN7QXTWzvdN+GNTKU5DpSJUKYKLRaBShi8UCaWCUr4Ijuy4NY8/9syNP/rPg6mYf3bSu9+zpTJj3/FhaG0YRWRsiCC0yFkLgAWgzFgSMkYBQL0n74iZJRDxnDiHLM3Ue4eklVCaZVlt3fr+3j/8YYrWG7NOOfeTT86cP+8AybIdaLRI63Uy9ZZKowodqZOv10G1WiLVxiD77CO7VPPqkaG+aSMjAyfvf+ONL0kTXxLAa9//fvN2p7+rlMdsYDbn7oQXhj+kSnkmd5cJlS5QpSwoly2KBUGpRFTIj92+YcP663/4g/2CSZMfnnrG6T6sdHUXopByuYKGoaEwDBGEIaIwJGOMhGHovKfEGPVBEGUAkGVJoEqGCGGaJoH3npPUiXcpxXGKJEmRpC3EcapxbWR463X/bZLebQvf95nPrpm4777TpNUYQD1WrtWdr9dCDI8IqjVItcpUra3WNPvMzjqpfH9kZOCACQGd/FL6xD8LUAHaccq7flEuj9/ARP+480YuvIzK3fO4uyzo6iLT1QXpKkMrZZhSyWTQiddd/r1n62lMsz/+sb6ouzKmmC+gWCxImMtTFAQmn89REEQuzIXKABtjhIgUAAPIOgkAAnQMlarCe8+i6tMkYeecbSapxs2WZGmszWaCRquOWt/g0Iaf/WxiJcxl7//8Z+ayoldrdaFaXTEyDD9cI1NtiBseUNtobHDN+FPP1Vkuqg4Pzph40w1nv2yAW4874dxKqZyzJnfZ6Hucz31fyuX9TM9YoKdC6KkIlbuYuyuiheLEbZu3rL3h5z87aNJp77lp7PyDpuZLZZTyEQqFvBaLRQRRzufzeVimoANsAMB2AFsAbAbQByDZDWAEYAKAKQD2ATAZwBhVhXMuSZ3nZrNhm/U6teIUraSl1ZGGDj3xWO/263+76D0f/chjEydPmaWN+nYdqTKGa0B1WGRomDA8QjpYfRZZ/HejdXRZfF6tWfeT77rte381wIHD3zpfQ/s3xfKYL0GVAQA2+iF3lWfpuDFK3V2Erh6Ysd2qlRJToTD3jzffcseza9dMm/s/P7clX6wUKpU8R/mCVkpFLRSKEgTWWmstgEEATwNYC6Cxh3IJgKM6fy9HWyu1c4861wUAswDMA9DtvXdpmvp6vW6arVQazRparRZqQ0Mjq//9+/vvt/9+a4898Z3v0Li1CsNV9cNVz4ODVoeqIsNDHsNDG5G5tiaqukZ96JLM61WT77/nqb8Y4JPz54djw8LN3eVxUxS6PwCA7a+op9JF3V3MEyYQuiqCMV2M7m4gCg/6f7/573uauUJj9t+eXSiXyzaXK3JXuaiFQh6FQsExcxnAJgDPoK1xhHbTpA6g7g6UgwAcDmB2pzhrANwP4KkO7CoA34HoOq9jOp/b13ufJEmi9XpDq9Um4rhOtVrVr/np1Y1CKy68532nH0NZ+gQGhtQPjxCGhlX7Bw2GB70OD4/A65JOvqtGagPbJrK8kx56aI/TPrM3gF8ZO/HfugpdG9W5U+EcyPmnqFioarEYULkCKhWEymVGpUxgc9A11123ws7cb+P+HzprXHdPt+0qV1y5VOCuroqGYRgZYzIADwJ4Fu2mWQHQIyIREUUAciJCRJSo6qeI6NsA7gZwO4ClqvppIrqpU7xIRPJElAfQg/YSWQJgG4AhZh5rrc1HUZgGATMRGRuGKM87yA5v2Tz02N33NOfPPeBQUfSyS1nTDEidauqIUie+Uffk3AQ4NzYy9prBZv307/bt+N1LBrh1zpwDQoTTAzIXtKdO4jSMbuJysULlippKCShXiIolImsPuf6m3y+LDpy7ZeYZp0+qlMvc091FpVJJy+UyBUFQYeanADwCIBWRkIjGiMg+qjqWmaep6nxVPY2IjlLVJ4joMACnAzihkxYR0TCAR1T1M6r6FiIqEVFFRHKqWlFVUlUhohjAWiLKjDEzoyhyxhhlMrCWbGn//UrVoaG1Ty9dGs+fvf+bSWgL0tSqy0BxBmSppSx7FnE8H84zvBzjnLvhf47r2XZpf//AnwWoAFXHTfivclSeR0RTAYA4uJIqpamolJkrJUi5ApTLxLlw9u0P3HdPOnnS0KwzzpjQVSlTsVhAuVxGoVAoMHMOwOMiMkBEkYgAABMRqSqJSAqgn5mfVtVFALYC+Bu0jchVAG4AcAeAJ1R1tqq+T1WfJaJ9mPknABqq6gDEABLvPYjIEFFJRFJVbTDz5CAIDDO1mNmoshRnzOgeWr9+oPfZZ9fOnDr1MFHpJ+cUzqv6lJH5IpL0VqgcAQChCcstFy+6ZKD/Z1/7cwA/PWfeCcWwMMhsP94mqiu4XAJVykzlElG5i6irCCrku9f2bnnk2aGB8rxzz43KlQrKpSKVyxUtFAqWiLyIPKWqCYBJqlpBu5/qEZGJzDybiN6jqkd77+8hoveq6nYi+g4RBar6QQDvBPAOAAuY+W4APyKiBao6A8AtqvpFAAtFBERUZOYKgPGqWlTVHiIa6qRyEAR5a61T9T4IIi4fOCdcd+/SfJGwprvctQ9EEnZi1XmFc6Qu60Ka1gGaDMI+AfFlQ2PG5i7p37F+V168u/YJ9KvWRl/a+UCY+xNyUai5HFMxUuSNIoyQthK6f+XKhQed9/fVUqlIpWKBS6WSz+dzQfurcC+AQe99WVXzqtqtqhNVNSKizap6u4iUVLVFRBc5574IYI6IXOK9f5+qiog8IyLPqKp4798nIpeKyH6qer6IfNN73xCRCjPfCmCt954BdAHoIiIjIkUR6RORZUSURVFki8VykM9HWiyW+KC//3zz/pXPLEySRCm0RiIryAVKuZyafJ45Ch4Y5WBN9EURf7HuZnifp4F/N3f+WwthfoTJvL/9Dt2ihahiKmVoscDIFxWFAlEQzvvtI38anvPpTy/vmjC+p1AqoburolEUBUQ01Tl3D9rW1DNzQ1VrzJyo6j4AFgFYSERLVfXdAC4HsICI3gvgSWPM94joZhFZq6pxpznfraq/Nsb8UUT2AfBhZh4G8FMAxxPRLar6BQBv8t73qeomADuYuQmARKSMdvew0FrTMIYVRAAQFvaf89T9N/x26gGTpkwn7/uQesCnUPHkY99NLlkNYH8AFct6SX+lB5cO9m/eCXZXgF79N4wJp47uvpgo2CxhYYoEgSIMlYKANLB2Ze+W28v7z0m7pk6elM/nUCzkuT20w1Tv/UYAbxWRhqqOrnhscs6tIqJbARyvqomq/j0R3QbgAiK6Q1VvJqKzvPcXqT5//2f0b+89ADxijPmi9/5dAL5MRLc4584H4IkoJKKbiWiMqh4gIlNUNWDmfhExxpgtzDwlDMMtBRHyzvvuqVPGl/af9ejqbVvs3DFjp0kQOAojFROQKQQqLtymSdrmwflPESenAjjxBQDXzZ8/iV1wO4CLAEAJd4kNpyCygAmI2KgGBkjdlCd3bJ+54NOfWFbI5xFFEedzOW+M6QFwFxFtUdXAew9jTMV7fygzv5uZ6977bxNRwXt/gTHmUlV1InIBM38VwDs6oG4RkbuJqLkbxAIRHUdEJzrnDgUQM/OXReQTAKZ0NPBSImIAnwJQAnAnET3mnBs0xkBVM2aeYK09wlo7kM/nDaA44MNnRw9dePFb9ytVMmbaAGtgQqPehIAJ9oFmfwTp20E4gNn+cu3MgybOWvfE9ucBDBJ5X7EY7dynZWOfhjEzjbWkAUOJiRRmxY5t901bfHItly9MyefzUiwW1Vo7SVV3OOcWoz2wtcaYDQBWiMidRHSqqm4jog+LyBZm/i4RnSci3yaii1T1Hmb+tff+QACnEdFJ2E2ICKq6XVWvVNWVzPw/vPff7IA8T1UvFZFNxpgPi8gIgAnOuduDIOgGcKyq7uu9Z+993Vq7PYqifYhou4jXLPOFKSce9/tH7vtTeUHPuGlK7MFWOTAiQQAT8FPe+bcDQCksjvVu5HQAPwQ6RkQB8mtXTwf47e3GQn1gM1WtgbckwqywRN6l4zYn8dsnvfWt46PQahAEFIYhq2rivV8G4Ceq+v9UdbWInOyc+4S1FqoKVf2Bqh6qqr8RkW3e+8tU9XYi+rKqHui9vwzAuWhb6UcA/MY5d7lz7nIAv0F7HNkD4FwiulRV91fVL3vv7/TeXyYiW4jotyJyqKr+H1UFM5Nz7hNEtNg5t0lE7iKiX6vqnUQUW2tNEIQU5iLd9x3vGLclTY7zWdoDqLbrzGBr4GH3VcWAAgDTcbJ29b6jP6xBW99nGJOfEYy0ijSmO1TCLRREPchFZIKANQyFQqPPpunq8C1HPjl+3oHlKMpRsVgQZj5AVR/z3p/V0egBVV0JYDEzbxORfQGMVdXDAPyaiD6JtrH4oYh8TFVPQnscdzkz/5f3fnVnnDiLiBYR0WGqKqq6XkRuNcb8ynv/eGew/W4imi4iXyGiyQBOZ+afiMhH2nqBsdQ2FhONMVeKSAzgMBF5LxGtYOZDiagPquS8mrReWxFv3jw4hrlIaQpJM1LvGN4ZdemDrDRG1qx9VLys+TvJNl8OjFgASGBO6Db58ar+fbxu3dUye78WDBMRVNgAAguHYJ1Lj15w8onLC4UchWGo1tqIiLap6urO2OwMVd3CzFd0xmY/VtVvA/gCgEtFZDERfUlVv+WcewuAW4wxfxCRt6vqlzpGAp0BN9BeUACAQzoJncEyVPW/jTF3O+feTUTfVFUB8CXn3BeIaKL3/nxmvkRV/5GIvq2qARF9QlWnA1gqImuMMbOCIAicc1k+r5h16ruKDz348JGzDe0gIAUzQExEVmBMitVr7obXsyObW5e6+O2Av5oAYC3s78YVxhypinEA1blS/i3PmlnWUtFSPgcuFCjOBc3l3RXz5i9/MQnDkHO5HIVheLCI3P6Nb3xDly9ffg4zR7v3XW8kEZHklFNOuf9jH/vY74IgKFhrJwE40Tn3aJIk2opjevDib+WPGm6lhTTNS6OpiJvQetPrug01P1x9L0ELRNgx0By4byb8aVYBXg+qimIcACj0FsTJOOzojbk40wMSiM90HezwtFNOrhtjJodhKNZaUtVCkiSz7r///hOZmc4888w/rl69etWcOXPmPP300ysPPPDAuc1ms56maQag55ZbbjnOWrvitNNOG2Fuj+H7+vr6+/v7ByZOnDh+zJgxY6655pr5ItKzZMmSezvN73lCRHj00Ucbq1ateteYMWP+dMIJJzQ6cPSZZ55Zvd9++80IwzAcHBwcuPnmm0+w1naXy+XbFy1aZP7whz/ozTfffHylUnnmrLPOeluWZZuCIMgZY5SIyDBj2knvfHbDdb8pz3U+r+otvCayfYeXZnOcQm8BcJoqJgCcKDzbTcCknA0fBnAWAKjyDiWUtZmEfv2mxM6a2VAbdG8L7SGHHzTv0SAIgPZofJyqPtJsNt9sjDFZlsVnnnnmMara6PR3C4noJ6p6HoCHmfmmW2+99bh3v/vdI2ecccYQgGUAzgZw3C7jvjU33HDDxlqtFpx55pk3ABhdUg+89wUAMwGcsHjx4uI555yDM844Izn++OMLAK7z3h9rjPlkB/JFInLm0qVL++I47r7iiisOyOVy5dNPP33pOeecs/K66657z5IlS54mopNV9XcAxllr+7xX2ufNC4sPXH/DvLnS6JPEx1i/UaXZKrR/S9422qtYGz603mUT2AP7Rhxyu89VcOADYnWqHuLSfLpxY5dWa9vZmO6wUCiTseC2+swTkY2jlSciiMjFqvouEbkEQE5VP6mq56vqId77LwPAtm3btqnqqar6HRGZB+BqEfmCiFykqqvCMDRERM65S5xzl3XSd1T1a6p6uqo+2Gw2vwcAvb29G0XkMFX9DjOfDOA7AH6mqhcQ0aw0TT0AhGHYA+A7RLT4Ax/4wB1ENHnDhg23qSpEZDOAedZaMobI5HIltcF4DNd28IZ1OfGuCCiUycP4YJRTyCEE2Jc9zFwY3rf9NqDe9DjhQAUW3oNcipH+HcmEgw/5PhEnDIWIKIC6qtZ362POArCUiP5FRL6lqjVVvURVfy4iPwKAKVOmTAbwsHPuCwB+5Jx7P4BLAVwgIouZmbQtN4jIr0TkV97721T1MREpiMj7SqXS5wGgp6dnkohc2fkBnhKRL3Ys8JUicl0QBKYzhLpMVb8BYOlJJ530NhHxt9xyyzGde0NEVG3rAKVgbk6cP/97IwPb1WWO4T2p91aFAxUaM8rJGp4CmDkWoDcTuON+RqmSlgyJI/Uq3nhKM9SisKX5cJYxrNbamjFmnKpuc869s6+v72cA/rGjhXMAbPbe30ZE/wLgHhG5jog+O6qp69atWy8i7ySiSzuWelhVrxeRx4wxSaPR+EC7K9GZqlrsXO9Q1Q1EdIeIbKnVagDwHVUlAJ9WVRDRJufcBcaYA7335xIRvPerOv3ol9FeFgPaq9a9jz766CTv/XcALGLm7QBCIhokIOJibkY1CJs5X/fshYyqcyQGRBEpUkBDEM0jaGYB7KekC6EEgj7JAOC9aHvnQSAW/cVSuO/cuYn3PmLmnDEm7UzDFlQqlb4OvGDZsmXfO+yww86x1m7z3v8LM39NVd/mvf9+54f77OzZs2eoatF7/x1rba+IHAngFAAf8N6jWCw+2mq1SER29SmcucvQBsVisQ4AW7du3UxE56vqJBE5tzOrEefcZStXruQ0TT/IzGi1Wl/P5/N/Q0SzmfkrY8eOPaO3t3ccgGNEZIGq3sXMKRH1QFXGzp2bbSyWypPTXqgXdd6BvRdVZEr6FBSHMnCYgBMLIA+lCgAo6RZRhFAFeQ8IQSwQR2FPYZ9JW4MgSK21LCJzRaRJRB81xnwNAIwx5oorrvhspynPEpF/BlC11jaiKDoZnd73+uuvn7Fp06bHrLVHhGGo3d3dEJGHsizbGsfxjoGBgTMBFK6//vqrjTFBtVottVqtuNFooL+/X7Msc0NDQ1MBvO3WW289aenSpUfEcVzy3ouIxEQUGmPOA4BRS++c+6SIVIwx53nvL91vv/3uXb58+SwAE4jooyJyjqrOtNauIiJXnLoPJ8Woy2cZwYuyqIoqoEgFWMvAoarUDaBgAfCo96sqWiA15L1CmMApICDJh/l8qcTGGFFVj/aUaqRYLP7L2rVrf9xoNL5eLBZ3aggzEzOHaO9VVJLkuU1+7/2MBx54YAb2Isa0V9h+85vf/Pk9WaKJrVZr4iisUWC7y9q1a389b968aQAuA/CMtfapOI4XeO8vLpfLX4vjeA3aa4gCQE0QqURRDmlKgEK8AAqCihK0iueGV8yA2tGOkYAUIIEoqfckzpPLHBAEFY4iEhFnjPGqOhbt3bGZ++6778l9fX3YsmUL6vX6zqWnN5JYa49g5lNV9d9E5FvHHnss+vr6cpVK5X0AphNRA8BY770AEJsLSYytqMtUUwd4bbMDRBWNUV6AWn6e87WSV9KmGtRhUGdwPYCpE1srzmVE1ErTNFHVLd77AQAwxswEgCzL0N/fj82bN2NwcBBZ9rKdP18xWbVq1ZPe+49nWXam9/4/DzzwwGcBpNu2bTMA0FmE3UpELWNM3RiTsA1CgOpgqpNBnRk1z9QU2J28aFT7dr5BmldFyQIqIPKq5OFh4evqfaiq+c48dC6AjXsqrPce1WoV1WoVYRiiVCqhUCigs+D6mkmWZWg2m2g0Grjqqqui7du3Hzt58uTbJk6cuHb27NnvJ6Kt995779NLlix5E4CJqjqHmR8CYLMkSQP4qgrKBJAwhKBgJVZyFjs9jwEreE4FhajIopRAGSAGkRG1CJwfcnEqlMtZIhIiqhNRcc9Ff07SNMXg4CAGBwcRBAHy7QVYRFH0igN1ziFJEsRxjDiOn9cCduzYcdbVV1/9gs/84Ac/WLFkyRKoahlA3XtPzjmbtVrMiWs66BgQiIWcQpVZQwJ17eQFwBLQC9UNIEyHoqJGYwhIIO21QvbepGktHhpyQXeFOyvNDeCFHvi7yBAzb+zkwSIyLcuynl0rZa1FEASw1iIMQ1hrwcyw1oKInmcQRGR0TREiAuccsiyDcw7OOaRpOrrcvyfZxMyD1PbBgfd+Ptq+NhgYGDgJAIhoHwB1dFQrHhlxuSyteUg3g4xv93VKYFJomaCA0hoCtliBPi4EQ8B0IZ1LgscZUKfwgIoQo7S9v9nYtDGMpkwxYWhtZ2B7SCfT5wkRPU5ErqenZ924ceNkx44dPDIyAgCbReTg0edGK/8qihhj/qSqZuLEiWvL5TJv3ry5GMexV9UxqjoTQNrb27u8VCq9mYgeFxEbxzE11m8Mcn39Dc8QFaiFAkSkKoZID1YlgOQhQB9lBT2tKqsAgBTjhaTmSb0C6kDGiQa8dWuhsWZ9TtVb55wBMKiqxjl3LwCUSqXfjsJj5vqiRYsmBEFwOjOfEUXR6SeeeOJYImow85OvJrFdxRhzfxRFQ0cfffR8a+2ZQRCc0dPTs3jx4sVpZ+q2paen596VK1c+pqoBgMHMeyYiaqxdVwy2bCtnQoEA5Nu+TJ6gI6o0BgC86rMCeoYZfnXm0+0Ytc3CDXiygASqYK9MNFwrNNavnZ2mKURERaQOAEmSbN1t2GIXL148pq+vb8p3v/tdiAi+/e1vo6+vb+qJJ57YjfbK81/syP1XyAZVjRYsWHDc2LFj81//+tcxffp0nHfeeXjyySffsmDBgg3MvKNer49LkiTqdA11FYFzHsn6TbN4qJYnBYmCFQjEU6BKzVFO4tMdgF9rCVib+Oy00OQAAMTUVFEVpUyhUKhFko5F4g5Mk+QOIgqIKGVmOOemX3vttXfW6/XjrLX3EpE89dRTxy5cuBDLly/HvHnz8MADD2D69Ol45JFHDmDmewE8rKrjXk16RDQwadKktRs2bFgYRRFWrVqFSqWCe+65B4cffjhardaihx9+eG2WZVOMMRYARCTN0hQuzRLN0nk+i58ASAOwCOANgcHaVGlb4KbPxjtgjd0fqK4Uf/ROWyxqASYlsVBWBbwCCPv778x6dwzQPvtMMsZoEASbVfVtRx111E3PPPPMzQBwyCGHFK666iocwXXn3QAAEZlJREFUe+yxePbZZ1GtVjF16lQcc8wxWLp0KRYtWrT60Ucf3Wl+X6lB954WXk866aSJy5Ytwwc/+EHcfPPNGBkZwTve8Q40Gg0sXbo0nD9//vJWq8UzZsw4RUQ2dgyVtjZtGgj6+m9X8EQAQlBWKBFYSBBqh1Mq/m3zgQvabrNAnwIPEHAEgBMIspJUIKTkARaFMQ89OlJbvjw/5vTT1DlHxpgnACyaNm1a38UXX/wxEYGI4IEHHsD111+PJUuWgJlxyCGH4Oqrr8acOXPwmc985m9Hnxu1qLta11Ggu7+OAtr1lZlBRM+7Hp3OjVrwG2+8Eddccw3OO+883HXXXRgYGMD999+PBQsW4Oyzz/5okiT/KSLjVPVGL6KNRoOaD64o24cfq3nIFEOkAlIDdYAnAb+jw+sBAtYBnV25v4OphWyHmPidALqgtEIIxbbnIkOg5KrDJT3ggLebgw9ew4aNtTYlonne+2IQBN2qyiKCOXPm4Je//CVEBKtWrUJvby9WrFiB888/H8Vi8Xnw9gZy1793T3vT3t21kIgwefJk3HzzzajX69iwYQN27NiB7du344tf/CKstS5JkhKAsSKyIm61qNVspcnd95yst92RWMAYYjEABYCxsIMKfQsAOPGXpz77w/cg6xkAArj7W65VHs1cGNsZpBYMQKAgiFIevX23tTas64vjmFqtFlT1QQBzkyT5xWgFp0yZgiuuuAJRFIGIEEURLrnkEkyePPkFkF4see+fl17KZ3aHfdRRR+GrX/0qms0m0jTF3LlzcfnllyMMQ2RZ9gtVnauqf0rTVFutBK11m/pNb98tqhIqoKTC3LbAqup3jPJpuVaXh/sTsIun0dMwf+zJd+0PxWRVPA7CjhSglgIJhDxAaSm/OffZT0+17z+9t1AscqlYZCI6Q1WfiaJoWmfF+AUV/nMAdtfCF2vCL9Zsd0/GmL39PRTH8QARzfYi1zXqdbRaseh//fe41uXf326ayZQA0BwMAlLJA8SKsUp4EwhbBlsjz86DPw7Yxb1NgEuc91e0C4qDFboDECK0zY4KyNdbU2iknqT9/X1JHEur1VIRuU9VD0iS5Jo9NbndwewN3p408M/9AHv7vr3lPZriOL5BVfcDsCxNErRaLcRbt/XpSD1zzXiSgtgAyvAwbSPSq4Q3AYB6fzmA/z3KbSfAEP7melqfNrppQqKtAIAhUAiAWD1BbO2XvxyJ7l52QL1eR6vVEieySVWr3vszvff37K3v2luF9tZ0X+z6xZrti/Wfqoosy2713p9FRMNpmm6u1eucpqkU7n/wwPov/m+DAGsgQgAZAhkoWDQZ5TKY1ueuh7/9BQD3BxLfNtHXdHxAPgyiEduZzzJAEFI3PDxO+3aMYP3GvlqtybWRKrz3d6hqMcuyblUdGm1+e6vYi/V7f8n13mDuCWKnTL1pmk4CEKRpeme90aBGKxa/ZsN237d9OKnWxrQdKEm4c9qbCcPKdLa2rcEvAG2c0nZofz7AdjOWC0fSxuiZCMuCHQYg204IIEoA9f7kqlLlqZXvTONGrd5ool6vp9r2OD04juO7te3L8qKa8FIMyksxIC81H1WNW63WU0R0sIjcFsdxVq/VEdfr9a6nn17c95OfFRhCFkohFBZqLKAQ7kfHi62aNtcmkG/syux5AA8GtntxBwB0BwAo0YcD5WFDpAYEA4YBQzPXvf26/75vzP0PlhuNmtZqDWo2m4MAHgLw3iRJfrWrEdj19aU06d0t8K4gX8p37CnvJEl+h7YP4oOtOB6oVqtaq9do3EMrituvuW4ZMt8TgikAwxBgicDKwyD9CAAocIsTN3th22N2zwABIIb8r6G0vqzd4jUnLD4E1HS2OgJAQ6KkuXrlfn79Rp9fs663Xq9ptVbzjUZjjao+AuCDzrlfAHhFNPFlal6aJMkvVfUMAA83m821tWrVjNTqlHt27WbevJmba9bMMgRvALWAsBIFgIA1BRAqgKG08TBBzt+d1wsALgS2irhAIT8CFFCcYYFVAUHzgIYAWRKyUF37o590j9u89ah0247eWrXKw8MjaLZaq1V1uYj8TZZlN6jqyN60cW9a+WLjwJeibaOvALamaXoPgLMUWN5KkjXDw8M0ODSk0rejf0LvjiPX/OA/ihaAhUoHIIekxJCVpLqkzUB+KOLsfOAFUZH2eNDmQ9ClcG5J3uZmKBBCKWcNDQsQCEQ8wSiIRMT0Llvef9CCQxZsjIKnHbikIgKgGQTBJlU9xTm3GsBqANN2b3Z7et2TMdh1/Lf7GHBPY0IigjHmHu89EdERAG6O47hvcGjI1OtNifsHBg5cv/HYJy765gbrfaVAxCGBilDNEWyOTaxCbwJhHIGqQ0ltex/kcz9re9/+eYA/BtynYaqG6HHDZhEIE6D6EClXAHgHYgAsBPLqo833P7Bm4cELjt1A9GhGWnaqEOdbzPS0MWauiExX1Z9re+Qf7KkP2xO43QHuCmhP0Dpz4CERuVZVTyYicc7dPlStJrWRmtZrVY37h/oXbu094bFvfXuFSZOxEZGNFDYCfA6MHDGp6nYiHA8Aqc++lIn//RGQPUb32OtZuR9C1nxc/GcjGz5JoIMBmk+svyPQBAACUqiSVVJIlhW3LLt/5eGHLzx8o8NTKUkh88555wNAN1pr+1T1VBFZx8w3icjB2j6a9bwmt2uzHJU9QdqLBgoz/1xVJxDRUQD+2Izj1fVaLalXq+FwraZZ//DWI/r7j3/4m998gprNSTkgyIE4YmgBLDkiWKUniXAOAAjwi2ra2Ocg+Ev3xmmvAAHgH6A31lz6oZzJEYCxUD6YCHczoUeU2DMMQCBSylzWtfHOu2tHHnXk9DjLHu/1bqzKzj4sZrarARUROUnbHq2/Q9tFrmtXiKPXe1p5GZ2K7QZvC4D/ApADcDSAJ0RkRa1Wy2rVBtXqVQwODMvkoZGtbxoZPuyBr3ytj5JkfJ5gQmWTJ0IR7AsEWKb1qvhIh8uq4WSkVYJ+6N/30HRfEsB/B9zHgWVO3fjIBAsIGhHRDIY+xNAygRVQgjBDlcW7YN0dd2bzDj7YTjXWPJVltVbqOUvTXOYz8c63VGU1M9cBHKKqU1T1NgB3S9uzfho68/Pdm+0uyRHR3UR0B4DtRHQgM5dUdV2apk83m83myMgI1RpNHR4aMLVavX5stV6sbNpaWP71i4qBl2IEaF6ZCyxSAEsemgXEW1RwGkGLANxI1riaVL4yp30YfK/ykmImPApzap7t3EKQ+067ctigwP2xYlwq4AYLN6AcgzQW9S0oeubM2fTmv/v0kY8Q3bUxF3bnCpHJBYFEUZ7CMEQYtnfjmDnsaOE07/047/16Vd3S8RZIvPdgZgugQkSTmHm6MWaYiDZ2oKejO3Rx6rXValAaJ9qMWzohTre9FXTy4z//5dLtDz64fx7gHLdHE3kYXxDhHINyxFsVeCsU+wKQetb6p1T844fA3/jn2LzkqB2PAOeUOSqHQefoP2EThP6YkUxvgnwLoi2QT1RLTZUkUTXehukxXzp/MJw8acyt3j1RZTOhkM/bMBeQNYHmcyEAAxMwhUEgaLurdcJmAUTtU/LS9kfU9jUABrIkJS8eBGiSJJRlmaZpqtV6S3oEAydZO6+1bVvfsv99yVjj0jBH5AsgHzKFecAVwFIAyCi2EeMoKGYBQJrF5zUlSQ4G/s9L4fIXxY15BPhqV5AfsRx2INIQAdd7yP4tQJseQQvQJpRarC4VlRQQU+5qHP2Fz6e5CRPG3dGsr9geBOMtIQzDnLBlCkyAIGBSJTWGoKoZGePEOQ8AbK1R7y0RWSfKDEWaeiiJpnEK5zJkzmfjVftOyOXfnG7v237vv12Wk1qtEAKImGxOyOZBvgClvAHyIDWglar0PwjtfjiV9Lx61iq8CfjWS2XyF0cuegz4+zyHYRTkvwmAFUiJ8WNRPTSGaqzwTYEkDI2hpuVhHSFLoGq7K4NHfvQjtfEHHHj8mlZ828NJq9HnsnHGhNYGhgwD1rYNhaq6dgwZoDM5sCKs4jLy4uEyp+KzrDsIB95aKJSmBdEJ2598+s4HfvaziqtWe3IgChQ2b8hHUJ8TQp5h8gREIEtKjwP4KLU9yKSZxV9IJPmL4P1VAAHgUeAjAduppaD0v9CJd2oIvxKlcgJfjAHTFLIxqcaKLGXlTGBa0CxTsWK40TNjZt9hH1hiumfMeEcs+sS6VmP1hjh221KniXrK4I2gHXiH4cnA+DwZnRQEPCOfs7ML+f0j4gMH1qy/88Hrfikj69aPZ9FijthZUBAxfCQkOYYtClHI6nNgH4AalrThFWd2CAwOp41/F3FrDwV+/pey+Kujtz0EHMXgT48NS3NBGI0XuAqge5TkgFhJEqiPgSCBaiJwKSRogbxTNY7IZ6rGkWYmFw10T506MnXBm3X89Olhvru7GJXLlSCKxgNAliR9rWp1JBkZafZt2JBufPghHtmyuUviZEygFAREYlXZErkIGoTgNMewEYhCIMsBlCMERvkpJX07FPsDACnuG0rrazzk8gXAn/4aDi8r/N2TwJgU+HlPWHqQiL/y3B39NROJE0yJiVwM0VQ0TIE0ZVgH+EzEZKAsgwYegIdmClivnCl5B2KFSHv8xWyhQlBjLElIgCOQDUFqAR9AA8vsQ4ADgc8BgWVKc2DOqQbM2KSqAYHeN1pCUflaNa0fTsCHDgGG/loGLzsA47WA2Q/4Z8sWXUHhQ9o+nAwFUkB/ysAYrzQ1IU0cqYmVxAGcifoU4IwhHmIgTI4FIuQEUAWI2lNGKFQIHZcxVmuElVgQgL0RmBDwAZOxgIQEEylcpBQxY6MRJI4weo4PAJ5pZM1rMnHuTcA36bnjZH+VvGIxVB8HZjvghyVbvCkw9hsKLXRuCSn+rzIEqtMzgnEKTQnkPJwzCJwCHuqkbTUcAeIERNSeAajCWoZqe2XcctuqBJahgUdmGUEAeEswgcIR0XoVWGqD43ZFqZn49CtN11rkgE8d3g7487LlFQ1CqwCtgDmVIH9bDIsPWeJ/1vYUa/T+kwq9j5WKRDQ5UwmFkHmAPRSOQOpJhSHtlcT2fI6gCiYigWGjsAplkBoAAWAMOBPVbSBtEOhotCMZjVYwdioXN9LGmwX844Xwv38lQyK/KmGQHwQCMmYJRD6UM7nbQms+D6V9n/cQ6VYAdwLUIiBSRQVAt5IaArwHgbQ9jFESNu1ItKbtLIFhIlQ73UQOwAlQmrRbzTaIc5c3fHyiMv9Cvb/2sOdicb1i8qpGMleAH7T2BPL6T9aYu3Im7CHQeXsvDQ1CZQVAI6QY0fZ0DqRaVEIXoF0gXgDVMXv7CoVeFvt0KPP+WGPoWwucu/Pl9nMvJq9ZLP0HgXFg89U8h+uZ7SWvRh4i7vyGZNNZ3DcOA171MPDAawhwNL8/sfllzuQ2M/EL9hdejojq5bFrTT1M/RmvVtj3Pclr/t8c7gRswdjfFzjHoOfCh7wcIcU9dYlj6927Xo1+7sVkz0d7XkU5HnDq3ftjadWVdNPOU6J/bSLd1pBWb+bdktcaHvA6AASAo4Bq5s1Xmz79tQKpoN3L/6XJAy7x2VXkzdfe9jJmEy9HXheAAHA00sdJ6QFR/Ye/FmCq+g9edeURSF8z5/Xd5TXvA3eXZRxcam00zMDukeX+nHwj88nYt/jnIvC+HvK6A1SA7jPhb4wJqtSOofBS5NpMsuKtLn3Pha/iGO+lyOsOEACWAXm1we+Ywm4iLPwzjz/mJNuSufT049vHJl5Xed36wF3laKClLjhbJHtEQdW9Gw2qZ97f5505940AD3iDaOCo3GNzx4HxVlZz0Z7ui8o/KrLlxzr3x9e6bHuTN4QGjsrbXHwXRJywnP8C7WP5AkHkjQQPeINpYEfoHpP7hRrapEr/0H5LL2fR8W/z8d/gNZymvRR5IwLEnYBlW/i9gJiACNBYXfOU41/ExeL1kjdUEx6V4wEnLlxCkCogfeqaZ74R4b3h5d6wNP/esDT/9S7Hi8n/B3LrBEUxxEM2AAAAAElFTkSuQmCC\"],\"useMarkerImageFunction\":true,\"colorFunction\":\"var speed = dsData[dsIndex]['Speed'];\\nif (typeof speed !== undefined) {\\n var percent = (speed - 45)/85;\\n if (percent < 0.5) {\\n percent *=2*100; \\n return tinycolor.mix('green', 'yellow', amount = percent).toHexString();\\n } else {\\n percent = (percent - 0.5)*2*100;\\n return tinycolor.mix('yellow', 'red', amount = percent).toHexString();\\n }\\n}\",\"markerImageFunction\":\"var speed = dsData[dsIndex]['Speed'];\\nvar res = {\\n url: images[0],\\n size: 55\\n};\\nif (typeof speed !== undefined) {\\n var percent = (speed - 45)/85;\\n var index = Math.min(2, Math.floor(3 * percent));\\n res.url = images[index];\\n}\\nreturn res;\",\"strokeWeight\":4,\"strokeOpacity\":0.65,\"color\":\"#1976d3\",\"tmDefaultMapType\":\"roadmap\",\"showTooltip\":true,\"autocloseTooltip\":true,\"tmApiKey\":\"84d6d83e0e51e481e50454ccbe8986b\",\"labelFunction\":\"var vehicleType = dsData[dsIndex]['vehicleType'];\\r\\nif (typeof vehicleType !== undefined) {\\r\\n if (vehicleType == \\\"bus\\\") {\\r\\n return 'Bus: ${entityName}';\\r\\n } else if (vehicleType == \\\"car\\\") {\\r\\n return 'Car: ${entityName}';\\r\\n }\\r\\n}\",\"tooltipFunction\":\"var vehicleType = dsData[dsIndex]['vehicleType'];\\r\\nif (typeof vehicleType !== undefined) {\\r\\n if (vehicleType == \\\"bus\\\") {\\r\\n return 'Bus: ${entityName}
        Bus route: ${busRoute}
        ';\\r\\n } else if (vehicleType == \\\"car\\\") {\\r\\n return 'Car: ${entityName}
        Current destination: ${destination}
        ';\\r\\n }\\r\\n}\",\"provider\":\"tencent-map\",\"defaultCenterPosition\":\"0,0\",\"showTooltipAction\":\"click\"},\"title\":\"Route Map - Tencent Maps\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{}}" @@ -36,7 +36,7 @@ "resources": [], "templateHtml": "", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n var $scope = self.ctx.$scope;\n $scope.self = self;\n}\n\nself.actionSources = function() {\n return {\n 'tooltipAction': {\n name: 'widget-action.tooltip-tag-action',\n multiple: false\n }\n }\n};\n\nself.getSettingsSchema = function() {\n return TbTripAnimationWidget.getSettingsSchema();\n}\n\nself.typeParameters = function() {\n return {\n hasDataPageLink: true\n };\n}", + "controllerScript": "self.onInit = function() {\n var $scope = self.ctx.$scope;\n $scope.self = self;\n}\n\nself.actionSources = function() {\n return {\n 'tooltipAction': {\n name: 'widget-action.tooltip-tag-action',\n multiple: false\n }\n }\n};\n\nself.getSettingsSchema = function() {\n return TbTripAnimationWidget.getSettingsSchema();\n}\n\nself.typeParameters = function() {\n return {\n hasDataPageLink: true,\n ignoreDataUpdateOnIntervalTick: true\n };\n}", "settingsSchema": "", "dataKeySettingsSchema": "{}", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 0 : (value + 2) % gpsData.length)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 1 : (value + 2) % gpsData.length)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"history\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":500}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"mapProvider\":\"OpenStreetMap.Mapnik\",\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"showTooltip\":true,\"tooltipColor\":\"#fff\",\"tooltipFontColor\":\"#000\",\"tooltipOpacity\":1,\"tooltipPattern\":\"${entityName}

        Latitude: ${latitude:7}
        Longitude: ${longitude:7}
        End Time: ${maxTime}
        Start Time: ${minTime}\",\"strokeWeight\":2,\"strokeOpacity\":1,\"pointSize\":10,\"markerImageSize\":34,\"rotationAngle\":180,\"provider\":\"openstreet-map\",\"normalizationStep\":1000,\"polKeyName\":\"coordinates\",\"decoratorSymbol\":\"arrowHead\",\"decoratorSymbolSize\":10,\"decoratorCustomColor\":\"#000\",\"decoratorOffset\":\"20px\",\"endDecoratorOffset\":\"20px\",\"decoratorRepeat\":\"20px\",\"polygonTooltipPattern\":\"${entityName}

        TimeStamp: ${ts:7}\",\"polygonOpacity\":0.5,\"polygonStrokeOpacity\":1,\"polygonStrokeWeight\":1,\"pointTooltipOnRightPanel\":true,\"autocloseTooltip\":true},\"title\":\"Trip Animation\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":false,\"showLegend\":false,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"displayTimewindow\":true}" @@ -54,7 +54,7 @@ "resources": [], "templateHtml": "", "templateCss": ".error {\n color: red;\n}\n.tb-labels {\n color: #222;\n font: 12px/1.5 \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n text-align: center;\n width: 200px;\n white-space: nowrap;\n}", - "controllerScript": "self.onInit = function() {\n self.ctx.map = new TbMapWidgetV2('google-map', true, self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.map.update();\n}\n\nself.onResize = function() {\n self.ctx.map.resize();\n}\n\nself.getSettingsSchema = function() {\n return TbMapWidgetV2.settingsSchema('google-map', true);\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbMapWidgetV2.dataKeySettingsSchema('google-map', true);\n}\n\nself.actionSources = function() {\n return TbMapWidgetV2.actionSources();\n}\n\nself.onDestroy = function() {\n self.ctx.map.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasDataPageLink: true\n };\n}", + "controllerScript": "self.onInit = function() {\n self.ctx.map = new TbMapWidgetV2('google-map', true, self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.map.update();\n}\n\nself.onResize = function() {\n self.ctx.map.resize();\n}\n\nself.getSettingsSchema = function() {\n return TbMapWidgetV2.settingsSchema('google-map', true);\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbMapWidgetV2.dataKeySettingsSchema('google-map', true);\n}\n\nself.actionSources = function() {\n return TbMapWidgetV2.actionSources();\n}\n\nself.onDestroy = function() {\n self.ctx.map.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasDataPageLink: true,\n ignoreDataUpdateOnIntervalTick: true\n };\n}", "settingsSchema": "{}", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"First route\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.5851719234007373,\"funcBody\":\"var lats = [37.7696499,\\n37.7699074,\\n37.7699536,\\n37.7697242,\\n37.7695189,\\n37.7696889,\\n37.7697153,\\n37.7701244,\\n37.7700604,\\n37.7705491,\\n37.7715705,\\n37.771752,\\n37.7707533,\\n37.769866];\\n\\nvar i = Math.floor((time/3 % 14000) / 1000);\\n\\nreturn lats[i];\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.9015113051937396,\"funcBody\":\"var lons = [-122.4261215,\\n-122.4219157,\\n-122.4199623,\\n-122.4179074,\\n-122.4155876,\\n-122.4155521,\\n-122.4163203,\\n-122.4193876,\\n-122.4210496,\\n-122.422284,\\n-122.4232717,\\n-122.4235138,\\n-122.4247605,\\n-122.4258812];\\n\\nvar i = Math.floor((time/3 % 14000) / 1000);\\n\\nreturn lons[i];\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Speed\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.7253460349565717,\"funcBody\":\"var value = prevValue;\\nif (time % 500 < 100) {\\n value = value + Math.random() * 40 - 20;\\n if (value < 45) {\\n \\tvalue = 45;\\n } else if (value > 130) {\\n \\tvalue = 130;\\n }\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"fitMapBounds\":true,\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"tooltipPattern\":\"${entityName}

        Latitude: ${latitude:7}
        Longitude: ${longitude:7}
        Speed: ${Speed} MPH
        See advanced settings for details\",\"markerImageSize\":34,\"gmDefaultMapType\":\"roadmap\",\"gmApiKey\":\"AIzaSyDoEx2kaGz3PxwbI9T7ccTSg5xjdw8Nw8Q\",\"useColorFunction\":true,\"markerImages\":[\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7b13uB3VdTb+rrX3zJx6i7qQUAEJIQlRBAZc6BgLDDYmIIExLjgJcQk/YkKc4gIGHH+fDSHg2CGOHRuCQ4ltbBODJIroIIoQIJCQdNXLvVe3nT4ze6/1/XHOlYWQAJuWP37refYz58yd3d6zyt5rr1mX8B7S5Xo5/0nPYaNFM1PY0gGqOhfAgQCNBGlWFFUAYEIeihigbhFdZQwt85BV5Gj9r/718R2XX365vFdzoHe7w6d77xnPkn4YpAtU0YiizNJcmPNkMQFkDiSlowHt2HNtGlTSJ6B+pTpsKTfKgTj3Pi8SMtFtEZnFs8d8dPu7OZ93BcCHtt0+OiL+FJjOiqy5K5dtLwD4PBHGvy0dKLYo8B+1+lAldv50FfmFzWX+84i2M3a8Le2/Dr1jAKqCHtl2y1wC/pEMP9ZRLBaYzF8CCN+pPluUkOKfB6qlmk/dBwTyt8eOv2AZCPpOdPaOAPjA1h9/SJX+TyGXuz0TZi4EcPBeOk+U+RErZh2YyMAyQJEoZUjFgtkCAEScgDyx1hmInTglqDj2U1X0WILaPbWvwHO1WummeuLONhaXHTf2wsfe7rm+rQDe133j/i5xPyrmCr+OouhSKPbdQ5fLiezTIYUBQGMJBgYWxMYSISZhbxgQT8wGAgDiwWxUvCiBxKhSKOqdh4OyV5+6XiEfK/kjVOXQ13apG+I0+adKpXaG0/Si0yZdvPbtmvPbAuCNT98YTBhT/8fAmEpHoXgKgPe/6gFGP0nwG8s2YykcaRCAYYQ5tKTkDVuArDEwMRF5AICS4VZ1AQBSr6oEgL36CBAvlKqIsyLOKQl5TZH4uN+TawDuY6o64lWTJX20v1S633uJNvfmvnbRERelb3XubxnAX26+5gDy6Y9HtrU/wERff1XjSt0WwULDmZEMawPOgilgQ4FaGCEygaXQMQyRMaxiUijUkAEAImIGAFURAOrVA1AmI1ZExGuqoqkVFefhyGtKDql4X4eHc6LxJof0VIVM3nVc4uXaHUPlo0Tpc2fv/zer38r83xKAd6y74iImO31EMf9REA7cpdVBY8NbA5+dFNqsCTQipkitBjAUsLUZNd4qm8AyjDMmJAIRhDzDEBEbJkBVAyJWQJ14AEaciIeSGicOgBeBWNHEeXLkXIM8UvFI4bVBCVJNfdk7STd5xOcp0LZzjIqV/eXq/4i61edM/eaN7yqAqpfzf62Nf5LP5lbko/DbCuxU4saEN1mN2kKTzQbIkuEIEWfVagRDEVkOyXCkVq0aDg2p9YYNAySVerU0WN1R27Jjo6ulMQ1V+ggAOgsjNRNEus/IiUFnYUy2kM23AcrivXh2RiTxjhx5iSmVWEWdpmhQ4qvwSBBrXVPfqDmuVsT7C3aZvKslyZcr9dpxdr81F8ynO/w7DuD1q/8y6kDw2872ticN0deG7wvQHXHmdxGK+1ibQag5ikweliIElNUAEayNYBCSRQRiYzf2rNtx11O/rC5d9dj+1aQyM2Pyz3WGozaNisYNWY7SYtgWA0A5KUVO4qAn3t4+lOzYt+Grh+bDwstHzvjA2tPfd1Z+39FTRhGpi7VBKrE4nyBFDKcNJL5OCerqUEXdVeEQb0mk8lECjR0euxe9cqBUOnoQ6RkXT78hfscAvH71X0Z5kf8Z0dH2CgNf2NkI0d0ZbmtElMtFVEAQ5BFIlkKb00AzFJqCGooQcJjv7t868P3/ubayZvua48ZlJt57xLjjB/cpTssXokK7IQNrbeoZ3pIRJm1aYSUW9cwixglZ7xNU40ppY7mr+sy2ezt7G1s+vP+EGfd/+fS/Ko5pH9/pJK04X6MUDSRapcTXkXJN46QKp1UkqNVqvpxVyLzhOajihh1DpVkmrJ7+uak/bbztAF6/+i8j62p3j20vbgXR+cP3LYU/Djg/KcsdEnIWERcRIk+hzWtEOYSch2U76tk1T6+84Tf/NCdni2tOmbRgy6T26WOiKDBhGFEQhrBhiNAyjDGiQp4DFgI8AChg1BGBXOC9p8QJ0kas3jvEcUxxnLgNpTW9izfdOqGWlve7+OOXrThk6qEHKtKehq9xIlWkvoaYytrwFYqlglgrcZxW+oXSz+ycpOLmnsHypDTIfuTNcuKbAvD2288x22dn7hrVnt/ATBftBE/CH2aCtqkZU6CI2hHZomS4YCPK+5AKHFB2ZNe2Nev/739/e9qY3KRnPzHtQp/LtnfkMhnKZDMa2oDCTIjQhghDC2MCCQITAyYxpmkhAIAZDDA7l4bOSeR9YpLEwfkUjXqMOE0QN2LU4waq9aGBX6/+d7O9sXnu3579jbVTx02dlEilL0FDG1pJG64cJX5IGr6MupY5duU1npIv7sTQ4196ytUDx8+sf+TN6MQ3AyBd8+L8W0a15zYw0d8O3ww4vC7ijlkZU5QctVPE7QhNEVlTRNYUjHcy7tu3fuuVSqXBF8z66962fMeIfDaHfD4nmUyWsrk8BdaYIAh9EFoxzExEysYoAQ5A0ioAEIpIBGZmAM459iKaJo6cT209TnyjWkOSNLRWi1GtV9A3sGPg56uvG1vIZ9N/OO9rM8jS9oavSOwqaEhZYh3khq9K3fdpXWsbvdR3MoYCV/UOVadcOvv2C/AG9IYAfue5j1/U0R5mIhNctxM8yvxLyMVpOduJyLRRnto1MkXK23axlB27sXtT1z//8vqDTt3vk/fMGnX4xGyhiEI2Qi6X1Ww2S7lCIQ3DkCxzQEQKYADANgCbW6UHvwcRaO6fAwCjAewLYAKAcao6UkRIBEniEtRqNVOrVKjeSFCP61oaqurKvqe237P2lnkXn/X/PT9l3OT9Eql2V90QN1wZdRqSuhukhi9T3Q2s9ki+NDzHWppeUqnG/qsH/+b7fzSA33ruI7ODIDh/RCH6KkEZAEINfhia4n4ZO0KzphN5005Z06aRaeOAcjP++4Ff3P/86hWTLjr08i3FfEeurS3LUTanhVwe+XxOwjAw1loLoB/ASgBrAdSAV232Gc0NyJGt70+27mlrzNT6nAEwDcBMACO892kcx1KvN6hUqWu9Xka9XsfgUP/Qjcu+Nf3g6bO7zj7urBNT1F+quxLXfUkaMmDrviQ13+8THdqYqvuLZpfq+qrJNXFDbrp87t0v/cEAXr5iduiTMQvHd2QnKDC9+bC9NUfF9kwwgvNmBGW5Q3O2SFkzAkaCg/71Nz9+2MTZ6rlzLs4Vi0WbyWS5o63N5fM5G0VRaoxpA7ChBVw3ANMq1AKoHUAewCwARwHYvzWctQCeaNUrt4pvgeha17Gtevt47+M4jrVSqZlSqepqjQpVyyX/8xU3VBHF2T//+OeOFbgXaq5fa75ENR3SarzDxDToYz846FTORbPRV7oHG9sm+qEPX3TEM3vc9pm9AfiBP53+T6Pbwo0Cd4aog4p/yXK+lDX5IDIFZDinGS7CckEM+JB//u9/e3Z8NGPTgjl/Maq9s8N2FNtcPpc1bW1tFIZhaIxJATwFYA2AtAVWh4hERBQByIgIE1Gsql8gou8AeAjAfQAeVdUvEtE9reFFIpIloiyATgARgCqALQAGmHmUtTYTRWHDhhaGYE0YYmbHEXZj//rBRc/fXTly5qGHEus2FUceCbxP4DShRJ2mvuIFboyqG5kNcNuWVM965MbNd71pAC99+vADA+MnR6F+TeAg6h1TeE/I2bbAFjVLBbJcpIDzZNke8qNf//yxKblZWz42+9Pj2opFbutop7ZCQdva2hAEQZGZXwGwDEBDRCJV7VTVfVV1BDNPUtXZqnomER2tqi8S0REAzgJwUqvMI6JBAM+p6pdU9f1ElGu1E6lqUVVZVYWI6gA2EFFijJmSiUIPsDbXmGT3b59V6Kv0dd334uLGYTPmHK7Q7lRi65DCawqviXWSrEm1PlvgWMh9KPbut+/77Ohtj/97d98bA6igo7aM+O/Ogp0l8BNFPQhyY2RyE0MqcC7Ia2jyGpksBYj2//WDCx9uk/EDZ8783JhiW5HbigXpaG9HNpvNMXMGwAoR6SWiUKS5KhERS0QqIgmAHcz8sqrOA7AdwCcB9AK4CcBvAdwP4EVV3V9VPwGgC8B4Zv4PIqqoqgPQYObEOadExC1A60RUJaLxURQaZqoRW0NEsm/xgI6u7rV9L295vmvGlKmHQ32vk0QdxfA+oYTq+Vgbi70mR4p6BEaKlTid98S/9f4MV7wBgF/66AEnFbPUz+z/VNTBiywLgxxCFDgwGQqR5wznOeR8+6p1657r6uopfu7wv4mKbW0oFvIoFovIZDIBEXkReUlVG6o6Fs2N/EjvfSczj2Hm/YnoY6r6Ae/9w0T0cVXdSkTfE5FsC8iTAZwI4DAAjxDRj0TkUABTACxS1csAzG39MHlmzqvqGCLKt1xZA0Q0QERtQRBkDZMngrcmNAeMmB08uHpxNsrz2pFtbft4TWInDZtSLE5T8i7uSKRS8XDjBX4fYbnusI2jMkt/tGP9rnjxrl+gICP4Riagrzb1ssKa4CkrYRhwwBFHYGSUOZJKo8oPP/vCoV846opSoZCnQj7HxUJRMplMgGblR5h5wHtfbE1oZAvIHBFtVtX7RKTQ4pSrnHOXAThQRK4BcIaqNkTkRRF5UVUTVf1462/TVPVSEfm2974qIm3MvBhAl6pGAEYAaBcR45zLiUiPiDxKRC6bzZpsNhtGUaj5fIG/dNTltYeeWja3ltbVcGgMZX1IWbUUqDUBbBA+OYxDPuDLSORq6KsN76s48MvzZnwwlzNDgaFzAIBAi0LKtGVtEQHlOaQCQpOHoWDWL+9+ZODCuV99cnTbmM5cIY+2JudZIpronHukxUWemavOuZIxpuG9H8fM8wDMJaJHVfV0ANcDOIyIPg5ghTHm+0S0UETWq2oCoA/AI6r6C2PMgyKyD4BPM/MggJ8COIGIFqnqV1T1YADbVXUjEfUaYxrOOcPMBVXdCmCutbZirQGIlIBwavucl2577NaJM6ftO1nJ9aY+YfEpvDryknamSNdAMQ1AGwxdc/DqDjz9k/7Nw5i96ixBSK/MhTRxJ7oUbracmWAoVGNCtRSCYOxLazfcN7VjdjK+beK4KAqpkMtpJpNRABNVdT2AowHUvffjAYgxZpNz7hUiuk9VT1LVWFX/iojuBfA1IrpfVRcS0Xne+6tUX33+M/zdew8AzxljLvPefxTA3xPRIufcpQA8EYUAFhPRSCKaKSL7EFGgqjtU1RDRZmaeGIbh1sh78s7LxM59R09um7585fqNdtqUMZOMMc4igE0DthSppcYWL80VTNbyX1QCPgNN1fJqDvzi0tnjQviObGia3Ee0JEAml+E8DOUo4pxaE4GUJz3yxJr9/vSIv+8uFAu2kM8jl8vBGNNJRE+q6grn3AZV3QRgi6q2AZjHzHNE5FEAp3vvv8HM8wFQSywvADAPwDgAi0TkPwDcBWDhcFHVh9FcXH9ARE4BMI6ZvyEiHwYwSVW/CeB0IlpERJeo6hwiepmIlnrvVzLzemZex8yDzDwZqlUikGGm6R0H66+evuPYafuNynvFkCCF4xjiBd67otN4C4GmEDAqTuVnR3++beWT/z5YfRUHio8/0dEe7DynJTUvswmmEiwxWcCDwGyee37j4ydNO6ucy+YmZMJQM5kMWWvHqmqPc24eADCzENEGAMvTNH2AiM5Q1W1E9GkR2cLM3yOiS0TkO0R0lao+zMy/8N7PBHAmEZ2C3YiIoKrdqnqjqq5i5j/x3n8bTQt8iapeKyKbjDGfFpEhAGOccw8EQdBhjPmQqk723rP3PrTWvhxF0Xgi6vHeayaTyx075fS7nlvxcPGgg8ZNIjHeSKRMdbEUIEHwEuCOA4DOvB25vSRnAfghMGxEFNRb7ZoM0HFNadFeIjvRgMFkhEDKbEl8Oqq7u3bs+/c9cXQUWo2iCGEYsqrG3vvHAPwEwL2qulZETnXO/Zm1FqoKVf2Bqh6qqr8SkW3e++tU9T4i+ntVnem9vw7ARQA6ReQ5AL9yzl3vnLsewK8APIfmovkiIrpWVWeo6t977x/w3l8nIluI6Dcicqiq/quqgpnJOfdnIvJR59wmEVlCRD9S1QeJKLHWmmw2hyAM9bhpp47q7q4d733aSVBlkBoNQGxgYPdVRZ82N5In9lS7dp42GgA483hMyUY0RXgwXzAjQgUtshp1WhOR5YgDzoiB0U2baqsPLB7z0oxxBxWz2Rxls1lh5gNVdbn3/rwWR68moi5VPZWZt4nIvgBGquoRAH5BRH+OprH4oYh8XlVPQXMvfIOI/BJAFxF1qupxRPRBIjpKVSe3dOtdInKbqj5PRIe3RHayiHydiMYDOIuZfyIin0HTfI4kIgAYa4y5UUQaAI4QkY8ZY5YR0aGq0kcE8k5NNS4t665u6G9r47xDCi8pqabsNbFe9WkoRvU0upYl8GunnqebX7kZQ00O9DipLbKjRfQTPWnXYyBTBxMBBiIML2IVkt20sf6B46d9rJjJ5chaQ0EQRAC2pWm6VlVXq+rZIvIXSZKELcX/Y1U9RlW/AWC8iJyqql9V1aOcc99W1SXMfAmAh1X1qy3O+rKIHCMiGRGptUqude9iIrqWiC4brisiDxHRt1X1KFX9qnPuowDGe++vUNUPishNLQkIiOjPVPVs7/02EVkLYHsYhtYYg0wm1FNmnZPftKF2lFPJisCIkhE1DFiFaNLr1i5R+PntGR5lFMcBLWfCxxbhrgkjgqMAjCKgkrWFX48KZ7RHJm8CziJLOXJpUNu4omAuOfbKOMxkKBOGHIbhHBG576qrrtLHH3/8QmaOdtdd/5tIROLTTjvtyc9//vN3BUGQs9aOA3CyiDxXr9dRrzfo2gf/Ljt1TpyYIMnWtQ4nVW2kNd+bri41fOlMADkQerb1p4/f+WGcaS9X8HOLUQIwCgCUdFGi6ehBt7k+3k4DqQ8cOd2+mQdPnP6xijHB+MAYhGEoqppL03T/J5544iRmpvnz5z+4Zs2a1dOnT5/+8ssvr5o5c+aMWq1WSdM0VdXORYsWHW+tXXbmmWcONV2jQG9v744dO3b0jR07dvSIESNG3HbbbbNFpHPBggWPtMTvVUREWL58ee2VV145bcSIEU+ddNJJ1RY4unLlytXTpk2bEoZh2N/f37dw4cKTrLUdxWLxvnnz5pnf/e53unDhwhPa2tpWnnfeecekabopCIIMEYGIyBjGCfufvmbpltuKY6a4LKkzCh8PpZu913g0oIsAOhOKMQTElyvYPrsY43IRP6uK8wCAYHrUo+gpiXoaG+LR0X5VaNgxNEAHz5pz6PIgMGBmBTCKiJZVKpUjjDEmTdPG/PnzPwSgLCJHoLlY/omqXgLgWSJauHjx4uNPP/30obPPPnsAwGNoLl+O32Xdt/a3v/3txnK5HM6fP/+3aJ2JAAi89zkAUwGcdOqpp+YvvPBCnH322fEJJ5yQA3CH9/5YY8yft0C+SkTmP/roo72NRqPjhhtuODCTyRTPOuusRy+88MJVd9xxx8cWLFiwiog+oqp3ARgVBMEO7xVzJ70/v2jdHbNGqu/16uq98WakmuQgANhsU98MRQwMP7N0iYxhUuybD/n3WzqlAMROROElzfY3NrXHrtTNFHTkMvkiGQNiZhGZ7ZzbPDx5IoKIXK2qZzDzd9F0T/0pEV2qqoeKyN8BwLZt27ap6hmq+l0RmQXgZhH5iohcpaqrwzA0RATn3DXOueta5buqeoWqnqWqT9dqte8DwPbt2zeKyBGq+l1m/giA7wL4map+jYj2S5LEA0AYhp0AvsvMp5577rn3Axi/YcOGxaoKEdkCYBYzqzGEMMgUWILRjXSopzfekFUf5wUKYXYQCoZhykcM08C+DMUMw7Rva8sHqHZCJFD1VtTDaYLuoe3xrLGH/Yu1NiZVtcYAQEVVy7vpmPNU9VHv/RUArgZQ9d5f473/qYj8OwBMmDBhPIBnnXNfAfAj59w5AK4F8DURmcfM1JrY/4jIrSJyq/f+XlV9vmVMPlEoFC4GgM7OznEicmPrB3hJRC4Tkc+IyI+897cFQWBay5lrVfVKVX30lFNOOUZV/aJFiz7YMi79RFQiIgbg2NrazHEHf7+70q1eGiwkROoteQkhOmIYp8DQBGUcYIVwOJMepCCAkBCooCAnUPVwXoU1rrXVoyi7nwgoDO1QyymwzTn34d7e3p8B+NsWFx4AYLP3/l4iuoKIHhaR/yaiLw1z6rp169Z57+cR0bUiAiIaVNU7ReR5Y0xcrVbPbf0ek1U1DwCq2qOqG4jofhHZUi6XAeC7IkIAvqCqIKItaG4LZ4jInxERvPevtK5fY+b7W+0eBGD78uXLx6nqd51z85i5G0Bore1rNJJsxuan1EumFo3w3mtKSupAMASNRJEACBk6ixWphWCaKs1tqegVUIWyiBcPIYhRQlLKhQccNDtW9YEIh0TkiciJyGFtbW29LfCCxx577PtHHHHEhdbabd77bzLzFap6jPf+X5o46Jf333//qWh6kP+P934HMx8F4HQA53rvkc/nl9frdYjIQbsw99SWy6opPvl8BQC6u7u3ENFfq+poVb1IRK4iIvHeX7dy5UpKkuR8Zka9Xv9WNps9n4j2B/DNkSNHnrV9+/ZRIvIhIjpMVZeoqlfVEcyQ6WNmpQ8+nyva9m4IO/XeQ1XFE6UKfYkUhyrTEVDEFkAWO4NuZAuAsPnDKlgFzih8ku0cU5y4NQiCxFrLAPYDUCOizxpjrgAAY4y54YYbvtwS5f1E5B9UdSgIgloURR8BIESEO++8c8qmTZtetNYeHYahdnR0wHv/pIhsrVarvX19fQsA5H71q1/dYq01pVKpkCRJXCqVaGBgwDcaDdfX1zcRwDELFy788JIlS96XJEnBOQcADSIKmfkSIsKwpXfO/bmItBljLlHVa6dNm/bIE088sR+AMUT0WRG5kIgmWWtfIWPcuPZJDJ9r90hIRVTEq5KAlBIIdYH0UCg6FMhZUvDvjSDVnZBhUhUSUijICxHCbDFXZGOMqKoH0KmqQ/l8/ptdXV0/rlar38rn8zs5hJmJmUM0jyPb4/j3h/ze+ylLly6dgr2QaepX3Hnnnefv7ZmdoyUamyTJWABoHvTtmbq6un4xa9asSQCuA7DSWvtSo9E4zHt/dbFYvKLRaKwF0E5EwoBENlKVMOPFkcJDCRBVUlEloLQTLgWz1987FAhImCECJVEh8Z6cdzBk20ITkIg4Y4xX1ZFoHuJM3XfffT/S29uLLVu2oFKp7HQ9/W8ia+2RzHyGqv6TiPzjsccei97e3kxbW9uZACYTURVNb7mIiIYmJIOwLUWqTqQVIqFEDFHV6nC7orDMBB22LOzhWbRC0LJRLalqGYqyQWAJVDPGVJIkqQPYrKq9AGCMmQoAaZpix44d2Lx5M/r7+5Gmbzn4822jVatWvei9/9M0Ted77/9j5syZawAk27ZtswCgqt0AtohIzRhTssZWDdvQkA4RtETaxAOqZSWWnXgR1Kr8/kTbG2ThtaAE9QQSZWIQ2EilFteyhoJCa4lxYMvf9xry3qNUKqFUKiEMQxQKBeRyudcVsXeC0jRFrVZDtVrFzTffnOnp6Tl2/Pjx944ePXrt9OnTzyGirY888sjLCxYsOERExhPRDGvtswACrz4m60pOqIMIBIX4ZqCYAWsZLXumAtid6z8A5DSvlgkKFkcMiBERqHUDiUu8994SkQCoEFF+jyPfhZIkQX9/P/r7+xEEAbLZLKIoQhRFbzugzjnEcYxGo4FGo/EqCejp6Tnv5ptvfk2dH/zgB8sWLFgAVS0CqHjvyTlnq2mFYF3VORnJICKwI2IFI0Qi7TCtLaYCVgnbAdoA6GRhaoPXhipIVJkEUCXP7CrleBAd2RHsvYcxpopmfMreaICZN6LpQWYRmZSmaeeuk7LWIggCWGsRhiGstWBmWGuxqwUFABEZ9ilCROCcQ5qmcM7BOYckSYbd/XuiTczcT80YHHjvZ6MZZ4O+vr5hx+14Va1Qa/M9WB0Asa+SUCcIRuAtg5QEBKDYrEJrwdhiIXhBRQyIJkMxQxQvkELh4RUq4kCJ2VHdOLiOx+YmmTC0trWwnQOgsvtoiegFInKdnZ3rRo0aJT09PTw0NAQAm0VkzvBzw5N/B0mMMU+pqhk7dmxXsVjkzZs35xuNhojICDSPRpPt27c/WSgU5hLRC95722g0aOPgWnbcW5VUBYCSJYBBChgQzWnt2J4BsJyheFkVr7Q6Hc2kZYU6ARSejCjZFN259UOrc6reOucMEfWpqnXOPQIAhULhN8PgMXNl3rx5Y4IgOIuZz46i6KyTTz55JBFVmXnFO4nYrmSMeTKKooEPfvCDs40x8621Z3d2dp566qmnxsxcArC1s7PzkVWrVi1X1QBAv/eeiYg2DK0upOgpiCBQIlIBBOrBOgTCCAAQ0jUQrGS1WF1vUPewLlTlKoQCOARewOqVUgzmtlXWTWuKiqiIVAAgjuOtuy1bgtNOO21ET0/PhO9973sQEXznO99BT0/PxJNPPrkDQAO/97C8k7RBVaO5c+ce19nZmb3yyisxZcoU/NVf/RVWrFjx/kMOOWQ9M3dXKpVRjUYjbKmGinOOnPPYWt04PZGhjHoQCZigAQsFpFwbxqlRpx6k6LI6gK5Kpz8zm20d0JHWQFAYTSUlALDexSNdEB+Y+nQxpZRlppSZ4ZybdPvttz9QqVSOt9Y+SkR+xYoVxx522GF4/PHHceCBB2LZsmWYPn06nnrqqQOZ+REiekZERr+T6BFR37hx47rWr18/NwxDvPLKKygWi3jhhRdw5JFHolarzXvuuee60jSdYFordxFJnHNI0rghiGc4jb3xUDEQEngyYEBrwx7KcuJHZzux1t79KZQ++iv5AHTnCadVBZGQhULh1SsIMfoe7KlsGRqTm5Q1xmkQBJtV9dijjz766f06bwAAEgVJREFUnpUrVy4EgIMPPjh300034bjjjsOaNWtQqVQgIjjqqKOwZMkSzJs3b/Xy5cstgFUA3rZF954cr6eccsrYxx57DJ/85CexcOFCDA0N4cQTT0S1WsWjjz4azp49+4l6vc5Tp049TVU3eu/hVXVbZUN/TH33k8c4DVRIiMFEohCjCIdXLC6VY+44DV+zACCEXiiWgnCkEp1EpKsEqqTEIsTq1Axg+eCy/kczp+QmqDZfuXpRVedNmjRpx9VXX32hiEBEsHTpUtx5551YsGABnHM47LDDcNNNN+GAAw7Al770pc8NPzdsUXe1rsOA7n4dBmjXK3NzgbHrZ2beWQDg7rvvxq233oqLL74YS5YswY4dO/Dkk09i7ty5uOCCCz4bx/FPRGSUiNydph71ap2W9T9eGGgsr4iqZSVVsLJ6Z5lIlU5srfmWAlgHtE7lDjgP5SjgAWb6MBTtoroMgpwoERTwniiJhwq5aPrxB+YOWwuQIaKEmWd573NBEHSoKosIpk+fjltvvRWqitWrV6O7uxvLli3DV77yFRQKhVeBtzcgd/2+exmm3bl3dy4kIowfPx4LFy5EpVLBpk2b0Nvbi+7ublx22WWw1ro4jgsARgJYVq/XUG/Uk2fK95+ypXxfrESGGUIEMhYGTP1ovQOYOr2+kcjvVt+K9c130cp4slyX4nDnBqYbRCAGkTZXUELIVtPeezeUu3rjOEaSJFDVpwEcmKbpLcMTnDhxIm644QYEQQDTPDvBNddcg3322ec1IL1e8d6/qryZOruDffTRR+PrX/866vU6kiTBAQccgOuvvx5hGKI15hki8lTz76lura/fUUt6F4siJIKCiREAakhB6BnGp1ST9lwbngJ2CfE99Zd4cPzIcDqg4xl4wQl64EE+BlyicCnYanHz4RMumviR9vO7C4UC5fN5JqKzVfXlKIomtzzGr5nwGwGwOxe+ngi/ntjuXowxe/s+0Gg0+ohofxG5o1KpoFqv6+LBn496dssPt6dcmWAtlCOCNRDKgJgxEopDoLRl60Cy5p5P4Hhgl/A2NbgmTuUGBeCBOUTokVZAtyiIFJSk5QmJlJKeyvaeer2u9XpdVPVxVZ1Zr9dv25PI7Q7M3sDbEwe+0Q+wt/b21vdwqdVqv1XVaar6eJwkqNdj9JY3bW9IKU5cZRwUDNPcuagBE2G7Kg5RAKnI9SD832HcdgJIARYOVdyknXtjoTpBoaRsTPOMHQy7fMutQy/qQzOr1arW63VNvd+kTc/NfO/9I3vTXXub0N5E9/U+v57Yvp7+VFWkabpYVc8DMJSm6aZyqcSNRk1fxOMHPb/5v+pQtWwgUBCxErGCiOJhXHYMuRkU4r7XAHj3aYhTAaC4rakI9dNkMMSWPBhMSsRKmjRKIyuuZ3Bzfe32crnGlVJJReQ+Vc3HcdyuqgPD4re3ib1ZHfhmVcDuYO4JxNaYetI0HYvmMen91WqVqo1YNqVdW2uutz9NSp3KTNpcxMEYgjEYVNULmvVxiwLVu09D/BoAAcAZXL6j7F9SBVRgiUwPkRJYCQaqrEoMWrrqp4WN2ZfmxXGtWq7UqFwuJyJyP4A5cRw/qKryelywNw7ck+58I336ZvtR1Uaj0XgewMEicl+5XPblcpXqtXJtk33x1KUr/6MAbnKdgQKsDFUVMTtUYFWBvpLvohRX7orZqyJU192K6tSz9Qv5HPcQaCpBZyvjRSiyEFIVkDioiBbL1W3LglGduWJ9LKDExnAtCIJEVU/w3t/MzIfsbiD2dn0jHbkrF+1qSPZkXHY3MMNX59ydaB5ePdNoNLZUqlVfrpSxOvO4earr5xvqvm8iGfggBFNIyiGYQwwQ4xwABqqLhmo+c885eJVf7NUx0gDE4iv9Q/JYc1+MDABvDJQs2DDYhlBmxD2Da6YNxOulW9dsr1TLWiqVtF6vrwawXFU/7Zz7TwB/FCf+MUuW1ylJmqY/F5GzVXVZvV5fWy6XaahU5q26asuA22L7hlbvR4a8NVAYKFsgMBACJZDm7mNHSZ41HpfujtdrovS7bkV58p/oRwpZ8zIIhwM0C0SLoBipCmqNnaHAhq3L7MT9D9mfhjIrrYRt3nu0fG9VAKd673+Npq8t82a5cW9ADdOb4bZdljfbRWSpNt9BeSJJknVDQ0MYHBqiwXRHd9+IriPvffpa4YBCE0I5grCFMRlSGFoF4DMt3ffDUtXLPfPxyzcEEADGnoNH01gWFLNmChQhgTJEOqiKQIQEAiPNU09+Zf3jfZNnH3yY9mVWasoFL16sMWVm3gzgNO/9KiJaq6qTdlfyewNv9+f+QNCGPz8qIgLgaFVdVK83egcGBk25UtWBel9f/4Q1x931yFUbYLWNIxgOoDYgDSJYE6IB8CEEjFKg1D2QdscVfHn9r/EaB+YeAdx8B9z0+Sgz8HxgeR6AMVB6hgzaVMk3Q/2JSQHvJOra+GTXlMPmfEi6o+d87NpTLyTeN5j5ZWae6b3fV0RuIaKZqmr3ZJ33BNzuAO4G0B7vMfOQiNyqzcBN8t7fN1QuN0pDJVQqJe2v9u2oTt9w0l0P/uNz3iQjghA2CMmEGXgOCSYDIqJuAk4AgHrDf7We6u/uPx97zO6x13fl1tyOtfucqRcXM+ZFAHNAmA2iu4gwRkBKos0jAVXy4vKvrHvslWlHHHZk2m1eQKJ5VfXOOauqG4Mg6FXVj4nIalVdpKoHqSrtsrzYed1VXAHsDaQ9caAQ0S0iMoqIPkBEDzWSZHWlXI6HBkvBUKWsQ2nf5uSA7SfeueTqFxPUxtpQAxMSmxBqAhKTBZhoBYALAUCBW3ZU/D6Lz8E1e8NprwACwKQv4nf1fvlUMWsJwEgC5oDpIVJ0EhGrJ6sAICCXuvYVqx8uzXj/YZPSWFbWelyHeA/nPRLvqwxa3XRN4COqugrNKPwx2ozifxVww1y3K4CvA95WAHdQ8xWHDwJY4b1/tlwupwNDVVTKQ9rfP6j19h3dsv+Ow29bdEWvUmO0CWBshowJCTZL3kQAW1pPTb1noPTK9oG0no7Cp9b/7LWi+6YAXP8zuMnn4rFG4kfnQ3MYgIgIU5jxDCmKCigBpE1xZlEfvPDSErffrFkU7BNQpSutxQ1PLo6zSerFi9RV/CvMXFXVQ1R1H1VdhGaIbxnAzgQ5u4vtLsUx8yMA7mPmbQAOJKI2VV2XJMlLtVqtViqVaLBUlUqpn0vloTofOhBVMptzv1h4dd4Yn7cR1GSJwwhiQhIbIjUBthBwJoC8ElzvUHqzKL5+/+l4zQuGu9Kbyplw4m04Ix/xjI68+W6r2gZifdI1dFSaEEtdOW2AJYG6hnqXEMaOnL7ptGO/+L5kjVks2/JjM5nIZKJAoihLmUyIIAjIGANjTEBEHSIyWUQ6RWSdqm5V1YqIpC3RDImoQETjiGgKM5eIaKOIDKpq4r2Hcw6NRgO1egzvUq3V6l5Hxhuys9OPP7T0lke7tj41nQNiG0FtBmojeBMR2yzIRNhKQh9U6L6kkMGq/7t6Ii8uXoDfvRE2bzprx0n/hc93FLiQi8x1zYq0CdAHvcdkV4V3Dupi9b6OgosR+wRGvU3PPuXSHcXcPiMGnvAvcJIZlwsjG2UzMESUzWa16SExZGxLGFS9sVbFK5SUAGBYWYoIMzN5BbnUgSCaph5xXCfvvSZJouVaw1NWejrfL3NK1a07frHwmpFsXcgRvA3hTRahNeRsHmKaXpZtIDoa0P0AoBb7SwZqEt+/AP/6ZnD5g/LGnHwbvtlZCAYzAYbzJwwo4U5xOl0aUB8jcDHUxUSuoQ4pJE0gmbCt9vFTLm4UM2NHDCxNlidDweiQOAyCUDkwFLBBEFhSZrVEqkDzHLEVAiA6PFBFE0pFkjhS9YjjVJ1Lkfg0sZ3SO+rI8NBSo7vvznuuz8S+lDMhwBbWhmRtVr3JgmwAmAhqAlolij+h5svfqMW4ZKiaFu49F1e/WUz+4MxFJ92GS3MR246M+bYSGEAizD8mJ4d6p+oa8L4OcQnUJzA+hhWnqU+gUdA2cPKxnylNHj/rmOrW9N7+F5JGOiQjyXIYcgC2zRejiVXFw5Np5Y3xMGxgxBMJPMSlFHtPUI1NG/eNmhNm8uODUzZse+nB+x78WVs9KXXaDMgYspyBNyG8iQATwIRZwIawYPOCQj4LICSFDNX9V6qJ5O5bgH/8Q/D4o3JnnfhzfC6yvM/IdvPXADpaLd0KoaJPNS+xmjSF1QYkTeEkVfYpGR8j9Q5WRKvjRkztPf5DC3j0iCkn+AQvlDdUu6rbXaPWn5KrCEEErTwXTTKALbDmRgSaGxNk26bmppoQc7p7ux546PE7ZHvfutHGUJ4DOGMRmEi9sSQcwgYR2GTgOCRvDFXVaJUU81sA9PcM+X92Trru+yT+8w/F4o/O3nbyrTiaGF8cUwgOIMZRreZegerDgB6YJiQSw0uqgYsh3sFrjMB5eE1gfAovHka9pjaM+ke2TxiaNnWujBkzOcxnO/KFXKHNBpnRAODSRm+lVh6q1odqPT0bkjXrnuW+oS3tLo1HsKGADIQDsAnhjEFAFgmHsDYCmYBSG4BMRgMQvQTQcYBOBwBVPN5TStd6hxvuPx9L/xgc3lL6u5N+hpGwuHl0u33a2N/nDiTSXxBIRHWCNMilMdQ7DSVF6h1YUxXvyKhD6h0CCKCCVLxa9YASKYlyK/AOIJAyCUFBDGImB4KlEEoMbywCCtQbQ8QhxFiEJqDYWLDJakBEm4g1UKFPDI/Rq16xY9AdZQzOXzgf/X8sBm85AeM5t8P0eXwtItYRbfZToOavCyDxKj81RCPgaKJ3iL1TAw9xCVgdvHcw6uBVm/pNvQIKpwJV2pkKBQCEFKoMYoKFITVGQQxPBsZYeLIwNoQQw3BAjiNEzNioQKzAebQzkJRW9lXcbXEqctx5uOryYUv1R9LblkP1+JsxjS1+MDJn7wkDuhKEHACQQqD4OUgExJPFq/EpqTglcXDqEXoPJYETDwbgROBVAQY7ABCIJQKYYQBYZogaWGMAMkhhEJiQPLMaG5BTlvWUsgXjvJahAxS1RqpfH6i5eYjxhfs/i7clj+rbm8VXQSf/HB8T4LOj2uwzgaF/0GZ2oeHuVqjq48zIQzHee4QiSLUZgwN4kDYdt0Kkqq38BM1XhYnAMMwKGDQ979y0rERIRbENQJWIPgDorF0m2Ei9Xt0/5N4njH+//zzc9XamRH5H0iAffiOC9gLOVeD8kXl7bxjyxYC+OqMv0VaoPsCEukAigNqg1EEEFlWBQKHUFC9SBoOYiEUhRDoIaInBiSgyBDpJoeN2m9qG2Mv1/SV3iir+s1zFbc9chLc97vgdzWR+uYIfugUnC/C3keUlHQXTaQiX7LUCox9en1XwIBENCqTcvM1FVe0gSAcMzYVgxN6a8IrrBit+IHFyrCF850Orcf/ll781Pfd69K7l0j/mJxhtLb4+ot2uDy3t1T30Vihxeml/2U1WxpVLPol3PA088O7/MwI6/ib819j2YDOb154vvBVSxfXdA+nEBz6Ns4G3T8e9Eb3mUOkdJsW++NT2UjpHVO/V5vrvrRfVh7f3pTNLdZyLdxE84N0HEEtOgMsRzukdcBUV2vRWwYOnbTuG3HZXw4J3wki8Eb2uQ/WdojW/RLz/n+CluKaZTMhzm4eJwB9aFHADFf1X7+X6h/4MG9+LubzrHDhM934KLyhoaSPB3/yx3Nco42+811UPfBbvWvD67vSu/0eb3enEn/K17RkeNExXvPHTvyfxeuVQQ0be9zn50hs//c7Re8aBw3T/Z+TScl3niuBm9cCbLLeXGjr3mA3yl+/1+N9zAEHQ6oA/rxLLBPF49o1Fl54vxVJ08Ge/kwvkN0vvPYAAHv8K6ur8BbVEnlNF6XUArNQS/ziJv2jJ5/Cm07W/k/SeWOE9UddvUJ5+pimpYhODTtyT1Y29fsOrv2fxhXj+vR3t7+l/BQcO0z2fc0ucEyeil+7OfV7xFYXI4gvx4Hs9zl3pPbfCeyA67cfmFiaziVX/BgCUcL1XGf27z/vz8S7vNN6I3t23oN8caW0//+lcF/0PC+4VIBJgZm2aPw3/y8AD/peJ8DAtOQEuZLfAQ0sK7Q0rbv6SE/Yen/L/017ojH8LZ5/xb+Hs93ocr0f/D6s769KBP+5xAAAAAElFTkSuQmCC\",\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic3bx5uF1Flff/WVV77zPeIQMJIYQxYRRBpBGcQFEEbVQQUXB6xW5tWx9+Cm07IYIitiJog2P7qu3UCN22aDs0KIIyg0CYyUhCyHiTmzucce+qtd4/zrkhQIIogz6/9Tz1nHP22buG715D1VpVS/gLktnZjg3P2wGz3RC/N9hBCHtjMgOxGjDZv3UAkyZim4EHQO4i2j3UkxXUb9kkcrb+pcYgz3aDNvLjOah7BSZvRnwLX/8D2axILM0Dtx9ODgGGt/P4GNgtqD6A764i3+iJ44dC9CD/jaRXyqzXrHs2x/OsAGhrL9sB8W/B7ARKwz/H7TAE2btAZj89DbAW6X4HHRknnzgW7KdU5fsyeMKmp6X+J6BnDEAzhLWXHYz4c3GlG8l2HgL3frDsmWqzR5KDfpnOykkIL8D4OHPecIcI9oy09kxUaut//CKCfp7qtMuwwb8DnrOd5nOcXIfJCryAOgEpASUwh5HiBMwKEAW6YF1chIghthtqL97uSxG5C8a/TXvsBLx9VGa/8Yane6xPK4C2/kd7EuWblIZ+itU+BMx93E1OFmLchqQpTmaDA0kAlyDSwSwizkAFfN84RAfOQASLCVACDVgAESOGDZjmSDwEtYO20bVVaPMCionjiPoe2eXNy56uMT8tAJp9I2X10GfxyQTJ4GtADn3UDd6NYv5niKtgyQxcYjinkCSYi3gHikeSLhDwXjHzTNlWB4hEYnRAgoUSmIIqxAQsYEFQA/JRNHZw+lqiTn90R/VGYuNKQl5j/cTH5JD3FE917E8ZQFv23b0oJf9GNnQd8PFH1y7rkORKLJ2BTxJcAqQOSQyXGEiC+IB4wZxHXMABeIeZQ3q/MBQRhdiDNGqCaMSiYTFBKIiF64FYKBbAigKLD6PFsYjt+uhOcwHdiUMRe5fMe8uSpzL+pwSgrfje+/CyK1n1dcBeW/7wMoZll4Kfhy95SARXMsSDSxxkIInifIK4gHpH6kAlggjOOwTBJEFV8FIQDcQCGIh6ighOFdMELQKYYF1Bg0KgB2ZuxG4kFqvw+cmoDG7V/cXk7Z9iulx2efvX/1wM/iwA7bLLPIe1v4m4RSTJuWDJI/+675OUB3ClCmSC9yA1cKn1dF3mSFLDRJEsAYk9wJxSTEzQGW3TXlEQC6G7sde/0gzDZ0Zlt5Ty9Arp4GBfnBWCgxghOkIhkBsxGK4QYgs0gHZAQxPtNLH41q2GH4jhNFRfwrzK20ROis84gLbkohLp4C/IuAXso1v+UFmLlK4gLc/Bl4AMfEWQDHzZIAFJhKQMLgWzhMayjTz0kyYbrt2T2Nq3a5WFE3HWqgYzNxeU81ao5ADVpJ2ldLI6G6YN+o3zStI+CF+9n1kvWcYub6hR330mIgEtIHSAYFgOVkDREegYmoO2QfOHCJ3X4thqDirn0rUX0Kr9rex/Uv6MAWhLLiqRDPwPafdBxN79SC3yS1y9S5JVoQpSEnylB5wrgSvTAzCt0Vqzmfs/32By8cs2xZ2vXGJHjo/KnlVz1aEsLZsXKVQkpIlXTHo6T8wFjU5iTELULFpEQmN8Gsub87lq2gy/5pUM7ftb9jtjgNJO07DQQHPBerMeYqsnztaGmBvabhNbVYivemRwfJWitADktbL7OztPO4C25KISvnolWWMN8OZHasj+L5Luih9QfAWSmvVEtwquAi4DyWay6aYHuO/8A1phYOkd9sbVTbdgVlYqJVk5wycpWZaRJY7E+2i44L2Y0Zv8CkgMCMQ0xOCKGAndnCJG8m5ueacba7pkw/Pksp2rvrkH+3/kXqY9fx+cbiA0HbEDdIzYBmvRE+12l7y1GRffsRUj/JBubR6xdbQsOK37tAFol13mOXjzzymNrQL+/pGnS1/FZXvg64IfAKkqSTnBVRRXEaQ8g7HFK7jnU/NHde7tC5N3RpKB4WqpKuVq2cpZSpJlkvrMSqVEvE8ty9JClSJJJIr44BwWY0xjNC9iWZ4HH2OUdrsjzpm1Wi3X6RTW7XZpdNviwsToQfodP92tPpj9z1nG8Pxd0M4mYtugEygaGdpWQgO05aCxFI3/+Mhg5WsUQ3vx0Npj5GVnh6cHwCVfv4x0ZAViH9py0WcXIpUDcPVIOiBIFZIauKrgKg6z2Sw8c0m72XK3uA+MuMq06dVqzSqlTGq1uqVp6iuVsqRpGtIsM++ceO8NEQQi0AGmuKAElAEfYxTAQowUeZBu0U3zTkc7nVzzvGOtVpdGqyHa3rTpUPvSjpVyreDgc/dGZB3aVrRlFE3QlmBtoxhXtPUQlr/nEVTceRQzd5c9/+GUpwygLf7Ke0jHykjrS1suavpV0vqeuDqkdUEGlKTsSQYUqcxmcvky7v38c+6yt/xqvHTwvEp90OqVTKrVitVqNcrVasiyTBLnUhEBGAXW9ssqYD2QA1MT3bQP4g7APGBOv0w3M4kxxm5RxG67nUxOTkq7ndPO29YYb9pQ55a1z3U/Opb9P3wXA7vtgbbXow1HbBk6aYSGoA2hmFgK+ggnxoEPYENR5r/3y382gHb/xQeQFm/Gr/0ImOuD9zXS6p4kg4ofBKkJyYD1gCzty9IfXlVsumuXm7NPrC6Xh6sDA1XJyhWmDQ1ampa0XM689z4FNgP3A0uBdr8vSk/veXpceFj/9y39/6ccAq7/vQLsCewHDMUYQ7fbtWaz6VqtXJutCWt3OtJubBo7rPjMXsmMA5cz/60vJ3TuJzQEm1TiREJsRsKEElqrcEWfE0UJcz4P2Q9kwfvv/ZMBtD98I6XW+QXZkj0Q9uzdLZcgA8OkdYdMF5KakgwK1AWfPof7Lr52vJk27qufVq0PDKTltOoGBqo2OFi3crmszrkB4CHgAXpc5vpgSf/7MFAD9gVe0AcHYAlwK3Af0AQm+gDrVmV2H8i5ZtZpt9s2MdGwRqNJq9WUVqsZ9m1f1BqqxAr7v++laH43sWHEhhAaRhjzMBkJExNgJ/XhWUK+YDVx9FWy/9nbnN4k27oIQK39FUqLFmLhlX1beB+U67jMIRlIGiF1kApen8PCzy0cYZ91Dw2/dadp9ZqrVWtFrVZLa7UyWZaVRGQc+D2wiR73zARKqhqccwqIquKcmzSz14rImUC135uWmZ0nIrf0fw+oqjjnhJ54d4AGPU6dJSL7VqvVoSRJOlmWSKmU+KxSssVjH6zOa/5g8453nn8bzz3tEHzpDrTrECeQKnjBJSmhdQ+izwEWkNx/Oez9ReB924Jpmxxo91+wl0rjjc4vO7d3wQKu8kP84CyyIUHqgh82/ICQVA7k3m9evybstXb98FtnD9Xrrj5Qp5RlWq/Xnfd+AFgILANSVfVAHZjVf4E1EZlhZs8VEWdm3xCRD/QBfqSjIhtU9SIR+XszUxG5T0Q2quokPV25EZjsv4wA7AI838wajUaDZrujk+NjyWSzyZzJ/3pwTnrffPb5u79B2wsJEylxUonjkTAhxPENaOcURBIADfM/6bT+H7L/6Uv/KIBmiN1z/tWS3TqESM81JMlXSQb3QIYgGwQ/CH5QoDaflT+7cXNjYGLl4Lt3qA/W3WC9rtVqxdfr9QxIVPVeYKNzzoCOqjpVLSdJUg0huCRJusC4qp5FT7wPAlYCP1XVkf5zs4DXAbsCtwN7OOfO7nNiRk+EWzHGwntvzrlSn0N3APYzszjZbE50Wu1sfGKcZqNtu05+ffO0aitlj+NeSphcTGyATkCcgDhmhInlWJziutst/E1D9v2nIx/rmH08gPd+7ijSpc/BRnpW1+RWXGUd6WCGH+5xXjJo+MFhRpcu6q6+a2jJzHO65UpdBgeqbmBgwMrlciYiqqqLnXOFqk7vc4WPMRpQTZJkB1U9FEhF5Fwzu9DMbnfO/VBEXqyqrwGmHKW5c+4XZnatqr5dRA7y3p+uqh8DVFVvE5H1QAtwIhLo6dSNzrkKsEeMMQ0h5GNjY9rpFH5iYizutemTrjTvuS0G91iANcYJE544HoljQpyMxOZcsAN7SM3+AHHPhbLvP/9ua7zc47jP7OPEhz+KdcA64MIdSJKBBxFFpPcGigmx1Tc/f9G0syZrtZofHKi5en3AyuVy0gfveufc5qIo6mZWAWaZ2Rzvfdl7/3AI4SozGzCztqqeG0L4ELCPql4QYzzezFRVH1DVB8xMY4zHq+qFwHwzOyOEcF6Msamqg865K2KMK0XE05vaTDOzUgihqqojqnqD9z5kWZYMDAwmpVJGvT4gS6af1baHbzyY0FQwD67nzBVngMNz4xYcbOXHLMRzzEy2CyB3nfdicQ/8FOvMRrsQu78A2xWJYCaY6zGwxf1Y+quwbNrp19QHB6u1Wo16vUalUk5EZGdVXaiqQ3meO+/9BhFZrqqr6OnAE83sH/ttV4HvAB3n3Plmttg5d6Zz7sNm9i0zu69fvqWqH3bOnWlmy83sAhFpiMh/0JtgO+/9e1X1TTHGATNbb2YPOefGVbUEDKvqQmBOqZS5wcE6lXpdqgODlWXTP/Iblv48RePeOOt5wrUvpZrvDt3/7WMxS9zi/+aezx2+NWSPssImeqbY4j23XJDSeszvBAJODFHBWcrIA1c1sr1zN7DHjqVKhUqlQqlUcsA8M3tQVV8MNEVkjqoGEVkLPKCqVwEvA3Iz+yDwG+BMEfmtmV0hIifHGM81e3T8Z+p3jBHgTu/9h4qiOM4591ERuTKEcIb0JCMTkSuAGWa2v3Nujpk5MxsFEhFZ7ZybWyqVHq6pOrQaJuPOcxvNve6sjy2+l+Gdd8EkIAJ9LFHWYFMLokXvN9vzQWCLE2ILgPbA53bS7qrfi3WP7l+6GvxcJPRG4Kwn5LE1l/FVu63e4fM31CsV6pWKZVlm3vshVb0S2BBjTAG890PAAar6ahE5EjjPzOohhLO89xeaWQ6caWZnAS/vA3Wlqv5eRFqPAbEmIkeIyCtCCAeKSEdEPqaqfw/MVdXTReRCEXHAe4B6COEqEbk7y7LNIQRCCEWaprO894eWsmyTxuhDCG7NzH8s77X+jBcyML2AsBIxQ0xwKgTdCcl/h9kRwAJh/fds4blz5aAzVz+aA7vtE527fi7WXz87/wCwO+ZAVIgFuODZuOqmkfrrJirV+k5ZkkiWZWRZtqOZbYgxHglUnXOJiKwMIdyRZdnVIYTXmdl6EXm7qq52zn1BRD6gqv8CnAtc65z7sarua2avF5GjeQyJCH3R/IaZLXLOvSHGeB498f+AmV2oqqu89/8nxjgmIrPSNL0qhDAjhPBiM9sdiCGEpvd+JE3TOTHGDZVyOSpUNtVe/fMZI9cNMn32LliMmBnmIs4ghnshHtHrybU7Iq9/A3DRFgDNEL1l/U6uUhzRN8wbUD+vF8PAepecoHEandburbkvv7mSpZTLFSuXywnQCSFc1xezIefcc83sOOCQoig+18fgy2Z2gZl92cyON7MvAb9wzl2vqqfHGKfW2rmqLnTOPaiqK1XVJUkyD9iD3grlPX0wNwIfU9WXmNmXzGyVmf1cRN7rnDtdVS+MMTpVfTcwA/gVsFBExsyscM4dVy6XnRmxiGqTw6/cYcbqKw9nmo6CbEREURFIDPW7IGETyAwIL9PO+oZZ7516gLOP/budTZfuIXp3FT89Q9yvcaUhpNTzKLuy4TJlcmLZWPqi+2P9wIFqtUq5XDLv/d5mdqeqntLXQaNm9gBwrIisMbN5fZ10sHPuJ8C7gbu9919X1XeZ2dH0ph8Xq+p/A8tFZJr1RObFIvICM9vVzB4Efq6ql5rZXSLyfOBvRWRXVf2EiMxxzh3vnPt2jPEdgJjZcF+kZznnvuGcK6vqwar6ehG5XUSeZ6YbBcOMxIrx20v5is2UXA0NPYesRgfqIf4Bs5l0H/yDWHUZq45eec63/jDpALTg1c7dNouox9Nafh1KgKRnrhWPakKINZrtlzSnv7ZWq5UlTb1kWVYG1hZFsczMFpnZ61X1VBFJrfeKvm1mL+nruLkhhKPN7MNmdngI4Twzu8Y59wHgWjP7sIhcaGbvV9WXqGpZVVv9UlXVl6rqaX0996GpZ/v68jwze4GZfTiE8BpgjpmdZWYvCSF818wwszSE8E4zO9HMVqnqMhFZm2VZ4n0qWVay1ow31Gg0DydaBTMH3qHiEGeoy2kuv4YY3wy3zUL1WOjLq133ritxP3w+2HSgQTrwc8p7DeBqDl/ueVxi1o7Nimza5VNFqVqlkmWSpulBqvrrT3/603bTTTed6pwrPVZ3/TWRqnZf/epX3/ye97znZzHGwVKpNEtEXhVCuL3b7dLpdGzmio9XZKBb4PIKoQXSNEKrS3dJh2LytfRiFqMWTvmDe+m3X5WYne30+kUbnFkvCC38L0U+HdZ2KO9uSMxw0Wh3xyanvXHCe79TImLee8ys1O125998881HOec46aSTfrd06dIlCxYsWHDvvfcu2n///fdutVqNPM8LYNqvf/3rI733d5xwwgnjU4MaGRnZuHHjxk2zZ8/eYfr06dMvvfTS/VV12pve9KbrZWrSvhWJCHfeeWdz8eLFr5kxY8YtL3/5y1t9cOyBBx5YMn/+/N2yLMtGR0c3XXHFFUclSTI8MDBw1THHHON/+ctf2hVXXPGyer1+/ymnnHJkURSrsiwrpWlqeZ6Lc07Gh49bOty4ZJB6UcXFnh+gvcbQfAbGlcDrwaabdcfMznYJt66Yha2+A3hLr4tuBGQIbWe0V7Yp7xlJY5mQPjfUD16YJok453DOzVTVmycnJ1/kvXdFUXROOumkF8cYJ0XkkBNPPPEgM/secBpwu4hc8etf//rI4447bvyEE07YDNwAvA04cqt535L/+Z//WTk5OZmedNJJP6PnsgJIY4xVYHfgqGOPPbZ26qmn8sY3vjE/4ogjqsB/xhhf6r1/N4D3/lxVPfG6667b0O12hy+++OJ9yuXywAknnHD9qaeeuujHP/7x604++eQlIvJKVf2ZiMzy3m/IshJh2iE1Ri/dn8I2o/lGOg8NQLeKCuDWYr04l0tX38rNuoOjU+zpdHHSW2EAKiWE0PO2FTW6K0qE8fWmyXBWqdfTNLM0TUVV91fVDVtzhqp+xjl3HHC+mVXN7FQz+5CZHaSqHwVYt27dGjN7jZmdr6r7hBC+r6qnq+q5ZrYsy7LEOSchhAtCCF/ql/PN7BwzO8HM/tBut7/Sr2uVqh5iZuc7514FnA98N8Z4ppnNz/M8AmRZNg04X0SOPeWUU64WkTkrVqy4sq8bVwP7eO/FewdpdQjxMwgTG2g9tAMxr6BqGBGTdAtO4QFH7ua7qLoXrjHvEQBtGmopph6LghZCc023M/yCr5mZgk2tCBpm1th61aCqJ5vZ9WZ2DvAZoGlm58cY/11V/y/ATjvtNBe4S1VPB74FvBG4EDhTVY9xzomqmpn9j6r+SFV/FGP8jZnd1Tcmx1er1dMAhoaGZqvqN/ov4D5V/ZCqvkNVvxljvDTLMm9mOOcuNLNPm9mNr3zlK1+oqvHKK698oZmpmY2LyIRzzkTEvEinW33ORbTXdqEbUQUjwUiINn0LTtaYi9meiWg8ACkO6GPQQaRCtBwfCyIlEEOHO6jf1bmkSJIkAENmtjaE8KrR0dHvAh/pc+FewMMxxt+IyDkicq2q/peIvK//tlm+fPnyGOMxwIV9Sz1mZpc75xYCRbPZfDO9KcjuZlYDMLMNZrZSRH6rqqsnJiYAzldVAd7br2d1COHMNE33VtW/FxFijIv6n2c6537rnFNVPRxYd9ddd80xs/NDCMc659aratk5twFI1dUXEJM2lnchRlwUMI+TKpCjZEjYT0PsJBJ1fxwHA2ByD6KG8wENAWcZBYKUM4b2ayeJK8eolqZJbma5qh5YrVbX98FLb7jhhi8fcsghpyZJsjbG+Enn3Dn9acyXVRURef+ee+65B70A0b/EGDc5514A/G0I4c0A1Wr1rna7japuvadwd9VHtkEPDAxM9EV4tYicEULY0Xv/9yJyboyRGOMX77vvPpfn+SnOObrd7qdKpdJbzGxP4JMzZsw4ft26dTNijEc65w4ErnbOdfO8GEqSxJLpB25ktFzDaUSDoNERDEQdjvsxDgQ7VFRDglgZo95TZPogJlUsRpCIRkEAqQ672ryuiQQRSVV1DzObEJH/k2XZJ/uK21988cXv74vyHqr6MTMbT9O0VSqVjqHn9OTyyy/fddWqVfckSXJ4lmU2PDxMjPFmVV3TbDZHNm3a9Gag+pOf/OSHSZL4iYmJep7n3YmJCdm8eXPsdDph06ZNOwMvufLKK1/5+9///tA8z2tFUQB0RCTz3n8QwLmesynP83enaTrovf+AmV04f/7862666aY9RWSWiLwjxniqiOyRJH5pURQastkxteowRW6g1tsVZgZiRHsIOBBjEI2VBNXe3kUAtSaQoma4QsEJFoQ0rbq0hjmX9yTKhoHRWq32yRUrVnyn2Wx+qlqt0g9R4pyT/pywBAx1u48E+WOMu91yyy27sR1Kkt7y/PLLL3/L9u6ZIhGZ3e12Z2/93LZo2bJl//2c5zxnLvAl4L4sy+7tdDoHxxg/MzAw8KlOp7PUzIaT3to+NwYMyUpYXiBqRAOHEdWDTiJTLkHFoYVsUYxCCwgQlRiFEAQtDEmHVBLnvS9UNdCLV7SA3efOnfuqkZER1qxZQ6PR2OJ6+muiJEkOFZHXmdmFIvK5I488UkZGRkoDAwOvA3YVkWY/LlOYmSVpDciGevtrQi/Or7FvPGg/YnCDc72NnvRKdEqkidDEaKK2DmMN4hLvk2az2eyISINe7GIDgPd+N4CiKNi4cSMPP/wwo6Oj9EXqr4IWLVp0D/B3RVG8Kc/z7+y9995Lgc7atWt9/5YNwKoYY8PMmnnezXGuRKBFpAk0UBqYTqDoFrxMSTDskTCJ1VCGCQgmZg4vZoZnMoa8UqkMls0siTHuY2YPbauzMUYmJiaYmJggyzJqtRq1Wu0JReyZoKIoaLVaNJtNfvCDH5RGRkZeOmfOnN/ssMMOyxcsWPBGEVl37bXXPnDyySc/L8Y4R0T2EZGFIhLE2ySiE5jMwBCi9QL+Ig7byotvWALxkXi/yRCQRMU5jFhYCXGaxDgeuk2DctL39TXpBcCfkPI8J89zNm/eTJqmU55rSqXS0w5oCIH+epZOp/MoCdiwYcPJ3//+9x/3zNe//vWFJ598MmY2ADRU1RVF4V0+TmahEYxpBBVBAog6ByJWe4ThIglqG3CyCmwepkNmKIZEwUV1DlTF8gZx3GBGGmN0fZ3x+B34j9Bm59xD9BjdqequRVEMbz2oJElI05QkSciyjCRJcM6RJAkissWCAqgqU/NIVSWEQFEU9L3M5Hk+NbnfFq1yzo1OratjjPvTC8azadOmV/bvmWNmDeecxBgTjZMSi9CIQYcR5zykeFUiINQQAZEHzeLaxDTeLUYKzEPcAWLcY6ZmipppjMFI8tEGzeXW9TtnWZYCrFfVA+jtBngUOefuEhEdHh5ePnPmTN2wYYMbHx8HWNV/BmDL4J9BUu/9LWaWzJ49e/nAwIB7+OGHa51OR60XtdsdyNevX39zrVY72Dl3dwghiTGaH1+UabGpFQszEg3OgSgizjnE9u8bkdscdqczC/ejyeL+Mm6WYQ3MopmoBefMJOk21laTxuKKmbrY83aPmlkSQrgeoF6v/wxARO4WkearXvWqHdI0PcE5d2KpVDrhqKOOmiEiLefcfc8kYluT9/7mUqk0/qIXvWh/7/1JaZqeOG3atGOPPfbYrohMAmumTZt23ZIlSxaaWaqqm83MVFVKnQdrne66ajRJXHSiEcQkGjaO0lvOkSxB7QHnE1lCHFyLWc+3H2l5xKtapqYuRpNue6ySFSsXhKCxv05tAHS73dWPEZ3k2GOPnT4yMjL3C1/4AqVSic9+9rOMjIzsfNRRRw3S24X1bJysXGlmpec973kvnT59euUTn/gE8+bN4/TTT+fee+89/MADD1zhnFvfaDRmttvtrK8eGj3VECzLVy0IjfGKRiOqOtRSU0vFaE3hRJi2nsKWJ2xuL9fa7Nc7t7HXtLNGjOwgaoWpYEoSY3emaPeAPG//CkoVEcmdc4QQ5l166aVXNxqNI5MkuQ6we++99yWHHXYYt912G7vvvjs33XQTCxYs4NZbb91XRK53zt1mZjOfcPhPkURk0+zZsx9cuXLlwcPDw6xcuZKhoSHuuusuDj30UFqt1jELFy5cVhTFXO990teteVEUxJi3he4+MXYjgDnUjAg4orWm9nJo2GGmm2bLEnnrzRP6k8MPe8QS41EwkwTFFIsaRIr25qt8vmY8uHlV770lSbIaOOKFL3zh/y5evPhKgOc+97nV733vexx++OEsXbqUiYkJ5s2bx2GHHcbvfvc7jj322MV33nnnI6HUp2nSLfL4PVJHH3307BtuuIHjjz+eK664gvHxcV7xilcwOTnJ9ddfnx1wwAE3NZtNt+uuu74GeKgoCosxGq1VY3lr9CoN7CjO1KI4ExEUxZNN4SSUXiwvu+YT/bCbbRLldoSDMTnSO1seogU1cTEXb2YyvvaOscHB31dG0zdrjFG893cDx+yyyy4bP/OZz5yqqqgqt9xyCz/72c94xzveQQiBgw46iO9973ssWLCA973vfe+cum/Kom5tXacAfeznFEBbfzrnEJFHfe87erdY8F/96lf86Ec/4rTTTuOaa66h0WhwzTXXcPDBB/O2t73tnd1u99uqOlNVfwVYu92VOe3rapMjCyei2lwfxXDOnMTgRQSTl4OB8QczVkJvcyPnvGnuJDI+ihWvAKaJ2kIzqmoiqhBUpNMZr8/ace8j1snzljrnvHMud87tF2Ospmk6bGZOVVmwYAGXXHIJeZ6zdOlS1q9fzx133MEZZ5xBrVZ7FHjbA3Lr348t2+Pex3KhiDBnzhyuuOIKGo0Gq1atYs2aNaxfv54PV+O33AAAECZJREFUfehDJEkSut1uDZihqre3Wm2X5+3unPy3x2548Kpu6sV7QROPpIL3XkYxDu8teev/Kjrjl+dctnpF71W1uFnjzvVHnIV+rSBCRDDBDDWl3GmM/LrUWTbS6XQkxqiqehuwT7fb/Y+pAe68885cfPHFpGmKc45SqcQFF1zAnDlzHgfSE5W+W2pLeTLPPBbsww47jLPOOot2u02e5+y1115cdNFFZFlGv8/7qOqt3W5Xut3cyvmDGzutkSs0UlLFMHEoiIlhbJjCR8PcIWLj1p4o90kvPegaSe/bC2wOcLsZY50CaRdYNzfJI6gbWL3LIe+euyh9+4ZSqSKDg3UnIieq6n3lcnm3vsf4cQP+YwA8lgufSISfSGwfW7z32/s93ul0NojIfFX9z0ajRbPZtP35wZyVt/zbKomTcyspVkqFSoaWUkSEGcCBmKy2uN9id9LCl8NWu7NU9UKsdHEf5YMFNgjgpLcBFpCiPbkTYbKgvXp9nnes3W6rmd0I7Nduty/dlsg9FpjtgbctDvxjL2B79W2v7anS6XQuN7MFwPV5nlur1RLXfXi9FRPtojM5B3D9bXwighNYh3Fgb65culgtfmEKty0A+qHWFZrvNG/LPEddI3WGiLkE8JiKt/TB2340viD9/X7tdtva7bZ18/xhM5swszfGGK/bnu7a3oC2J7pP9P2JxPaJ9KeZEUL4dYzxFBEZy/N89cTEpO902rpP6boDlt98adNjPsE0wSQRIxEDle4ULhp3nu/Xt696HIDy6qVd1Asql/ZMdXy7F5ssiUURvDcRr1i3NT5DWxsmKvnitZONhms1m1oUxdVmVu92u0NmNj4lftsb2JPVgU9WBTwWzG2B2O/ThjzPZ5tZmuf5NZONhmu22jpkS9fE9sho0R4fRhDvRRMxSxLDY2OIvq0nmXIJKm05bWn3cQACOHFna5hzX1+MM8ytS5yId+AEBMErsui671b3Gbjn2G6n02w0GrRarY6ZXQUc0Ol0rrZetOsJOWFbYG5Ld/4xffpk2zGzTp7nd5rZc4HfdDqdvNloWrc12dqrfs+rF1373YokvU2ECeC9+FTEsGQjPbcfxLlLXJJ/+lGYPcr0n3LPerS8D/DbHhfaWxOxsVKCeYdkHhMvRAvDS2/58Y0H1X9fGZ9o0Gw26Xa7m+htAH99nuc/2NoIbP35ZET6sRZ4ayCfTB3barvb7f48xvhK4A+NRmt0YmLSJpsNe/70m+tLbrrsRrUwLe0fB08F6Z2rtzGI7+jpPq6MoTRfTlo6sl0AATq+/U+az76h/1AVlZg6o5xg3uNSj6WefHz9kj1orrCdSsvWTUxMyOjoZtrt9lLgTjN7ewjhB8CfxYl/zpTlCUpeFMUlZnYicHur1Vo+OTnpGo0GOyVLVkvzIR1bt3yPzBNTJ5Y5LHGQelPE5T1JBHTObb7onvFYvB4HYO3kVWuIpRSTb/aXLSd6WJQ6c5nHSg4p9xqS+67+9tCe9QcPk+66NZOTEzI6Okqz1VpsZjer6luLovjZ1jrxyXLlE80Dnwy3TX0C62KMv1PVk4GbGo32srGxMRkd22x0143sOfTQYXf+5t/qpQQyJ5qmWOKQLDHxxiLM3tTXfV/TIknlnSselxXpcQACuEp+Tsx3HERp9Pz/7kWZp1tySEkg8bjUiROscsvln1v7kl2Wvrzb2LhhbGxSxsfGtNlsPqSqV5jZ60IIK1X1uq3r/1PB/BNBm6Lr8zzfqKqvUNX/nZxsPjw2ttmNj08Smps2vnju4iNv+cnn1qVi1VRESg5KhpQTXObIUXdEP/bRiPnsHZzaJ7aJ1bYuykkPt73xbbR+Zu8N2P6ibqycQrmMlZ1ZKYVyIi6VOHzzjz9/99ELlh8dWhvXjI6OsmnTJhsbG5sIIfwXsIOqHhRj/Da9I1mPom0BsD0An+iZrWg8hPDdEMLzgel5nv98fHx8cnRs1MbHN2unuWHkmL0ffMXNl3/+LtEwVErFlRJcmpiVykgpRcXcJrB9eqJbP9OL/5q8c8U2T7E/4WnN8J2df+iTtQKc3If7KyGyf7ONNbqUOoXQbFtoBaJKZc3hJ33igF89sOPVOcNzhoYGQpqWy/V6RUul8qCZHqGqS4CFMcZTVHvO2a0t67asLvC41cTUiuIxn+qc+w/ghc65nUTkd3mej7dardhqtbLJZlMzHXv41c/Z8MqbL/nMIrHG9EqCr1TEVVOjVibUM0g89wFTx14viWHHkLxz9du3h5Hf3h8A57x++i9jrLzV+ZZgzACe6+B3HqYhaIw4J+JMkbwIQyvuvHryZS9//i6tXB9YuSFMC0Xs5W2KoeVElgCY2dFmttjMfk7v8M1g//qWds1sm56XKRAfc20N8J/0gvgvBO4piuKOZrMZx8YmmZycYPPmUXYb3LT+pXtu+ptrf/iJEbHujEpKUstEaplRKxNrKaTCCoR3AB6RJTGfPekle/s5Px3bbuzhjx64bn9tx92yrPigS8b+AcgQNqP8ohuZ28zxrQ7SynHNDtIulE5wxaEn/PP6WJnDT24faJfSSlKtlsvV6oCVKxmlXgCpDOypqrur6m/NbF2Mcb6qvlh7Z+keJbZbr3+dc8E5d4OILPXe7ygiR3rvV5jZgzHGVp7ntNtt2p3cmq2m73ZbjeOfN1nz3TXx1h+fv2PJaVYtOStnSK2C1lJirUxeSlmPcQwwo7e9b+gifPlf5e1rthm+fdIAAoRvzXytSHcv51rn959aCdzcDcxsdPCtHNfuIO0ca+UaWwEGZu+16pDj3vc3Ny1Nfr1oXW1WuVz2pSyxUqki5XK2dSQuU9VhM9vFzKap6gozW2NmDVUt+qcvMxGpi8iOwK5JkkyIyEOqOm5mRVC1kOd0Ojndbod2u0On0427zypWHLlv53X3XfWD69ctv3V+NcPXMmeVBKplQqWEq5eQUsZalBfSOw2PhuqHTct3J+8e+dUfw+bJZ+345vR3kbTrkE8dR1iF8LsisGujQ2xFrNUmtrvUmwXdboHP1RUvPOmfNyYDO02//BbuGu9k8yqlMlk5w7uEUlYy55A0TcQliTkRw0xxHouxd2Cot3PT+kcbxEzEQIIG0SISo1qet6UoAt08aLvb1uGyrj/hMD0gTK7ZeP2PPj+zlGhazoiVBK1lZJUSRb2CVlMk9ayldzJ+DwBi9gG01pV3b3xS2Yz+pLwx8RvDn3RZdwzrgyhsxvhJMPZq52izLVmzwFq5SbdLaEeNndyZlOutw97wwU5anz39ZzeHO9dPMCvxaZp4j08z0iQlSz1Kz/XhxHdxRFR7ESvnPIqPUTPV6LwX63aDKLEXEy6ChVDkc4Z15G8Pyw4qJtZvvOm/v1ixTqNaTpRSySXVFF/NROslpJwY1RKWeBZjnIAw1BtP9gGKclXevfmzTxaTPzlzUfzawBnOhwSXn9dPDpZj9i1DDmp2oR0Iza5qJzhrFfhuR5NOQdENTpPKwNiBx5w6MXOXfY9YtiZcef097e7IhE2XLMlSvDjn8IngncfMgllvQ7JzIoqkGsRUC4kWpCiCodadPuw2vXi/cmXBTslRIyvvvfauX/37YNGdnFbNVDJHUi67WMmIlVSpJs5XMqRWwouzuzB5J5BhqMbkDGflivzD+JMG788CECB8tfZO8cVOzsd/4pF8pz9CGOjm1DoB1+yStgq1dk6RF851g/puTtE10iLSGNpx95EDjjrFTZu928taOXcvebizfMWabvfhTV3f6UI3qqC9o6WC0ywVyiXYeUYp7rZTWpq/c3WPWsYBm9c9ePU9v7lEx9Y/uEOaUMs8oZSQVTJXZF6tZ22dK2eESkYsJf2NU0I/LwKjhPSLEb8i+YfmD/5ULP7s7G321cphEXuv98XeiL2gf3kxwu8N269VENtdF9sFaadQ6/aSDaXdSMgLfKFoEUhiJCcpjw7OnDu+497P1xk77pqV6tNr5drAoE/THUSchLy7odOcnOg2Rpub1q3M1y26zU1sXD1E6ExPElLv0MzjspRQ8iSlhKKSkpRTJ6WUolZSygmZiNyH8VKmMs2Z3BhDtlyRf83e17r1z8HhKaW/m/jywIy65N+XJP4B9JGljsiPMTSiO3cCRTt32im01A3keeF8oap57nxhWsRA0lEwJQQlMcNCz502ldqk109BEwERJHEEcSQlB6knJN6lmdOYlpzLnMZKQpZlrltJ1ZVLpB63CiPF7PgtfTT3KYv+b0TKb5F/HN/852Lw1BMwXobX9dmZmJrL9K3Agv5fOSr/jmdGVJ2bF3Q76nxRqHZy52LUmCsuj06jqu8qgjmiEtTUmEqF0vumgDlx4h2Jd2qJgHcuJk592ROT1PlSopomzpW9xiwl896tQumAvZlH0gcs1sJd4oTAxnCenP3Udko8bTlU7SvMN/NfFW9XAJ9iKmVJL/vkDzEM0V0Ldb5bqObRuagaikBWmLMQCKAuGAFDowKO3gpASbwDBJcICeI08SSJU8kceZKSpGCl1EnqNWJuBYLD7C1bsmBCC+MTMcqrfIjvlQ+y/OkY99ObhNaQ+K8ch+OdPnG3KXwco7xVY/eqyY3iqRk6xyJZUFeEqC4oFOYExaKh9JzaPSMiGOLECw6HpKKWeMyLI/XqxVMIbq1Fmk7scIP9txphxymfiUGfD3zL/3/84ulMifzMpEH+Bmls8yaMU8y535rnNOnP8rdqeA3I1eKsbSolB4NRdFgMb0Y0wcR64mXSSzggggeCw40rTIizrqlUwF5msNOj+gArPVykhR6t8P27q1x2yHt42vcdP6OZzO1sXBjmKODDqvxeEjfN4ANP0JlRRG43GBdljN5OWDCrmWNYYAizgw2mP0EdXzJ0s1NeivDZZDNXP1U990T0rOXSty8wsyuchXMrTLjgmWhDjDNQ3a1kfEr+iY3PRBuPa/PZaGSKDKR9AZc47x6KulUuwqelbrnIqe5c+SdOFJ4+HffHaJse6WeKBKwyyVtDoQca/Eb7qbSfarHItVbovpUB3vxsggfPMoAAcjahW+KNVlhDlZVPGcDIWjFbF5U3yTNgJP7oeJ7tBqdo9F84wMOpivwjsmWS+6dSMLUvpsJ3Bz7CdpMkPpP0FwMQYPyznByUHXFy4Z9VgdrpzjE+7aN8+2nu2pOmvyiAAJvO44tmboNh5/1pT8qnPTpj+se3nRjx2aK/OIBmyKbP8FMzN6bY257MM+LkMjGtzQy89pmc4z0ZetaNyGNJBGtv4k2gczVy+5MwHHcRdVoROOkvDR78FQAIMO+LtIm8zYndr8bodqcrRkuwG73jXTudTeuP1/zM019chLemtWdzpCkvir2EZI8jBx9xCTfNOYvfbev/vwT9VXDgFM05m2sMgiinP477lNMd6F8TePBXxoHQW+6tOYsfFsrDpnyof/GiJGHmzp/mrc/2SuOP0bN7CvpJkICZ4+2rjF8G5RcmDDrHvjt7Xv3XBh78lYnwFMnZhOg5SRxF6hmhyUlyNs/o2dj/X9LKT7D/yo+y31+6H09E/w/wHJVcjfUH5AAAAABJRU5ErkJggg==\",\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHiczZ15vF1Fle9/a1Xtvc98780cEjJCAgkgiUwiIghCgqLIQyK2qI0D2g6PlmfbbaONCmo/habB4dF+tBX0KdC2PFGZB4GEgECYIQmZp5vc+Yx7qFrr/XHODSEkiDKuz6c+Z9+z9zlV9T2ratWwal3C6yh64YW8Y8Ex4431M4yhOQAtVMUBTOgRQRGEWvtBlJnRgGJABSthdIWHrIyI1l9y3339F154obxedaDXOsPGr2+anFL2TgXOJKZWEIYP5oslL0z7EtE8Zj4M0O49f5qGofKAF32GRTe1GnWTZOkR5DUi0muC0Nxaete7el/L+rwmALdde+34nOcPgei0ILK/j4rlLmbztyBMfkUyUGwT8f+ZNGojWeLeBchvjOR+Xvngqf2vyPe/iLxqABWg/p/+YqFR+WYQREsLXeUuMH8WQPhq5dmRVMRfUR8eqquTt7Din7rOOXsFAfpqZPaqABy88spjlPhfi8XytSbKfZxAB+3l0ZSZ7hXD6wkWCAggClURGWJSggUAUjivokRIoJpq6gkkyl5miOJYqNq9VO6xer3+UxfHp4P9l8Z+8pPLXum6vqIAhy+/fLYXXFksdd1go9wXQZjyggyJH1HDDyEIQ1iawMZAjAWTsWS55QHHbEREGQwPABAYZhLxzjDBIpOcQBx7BwhUvOtDkiXk/WGqcugeirbJxc1LGvXaqY5x7sTPf37NK1XnVwTgg1deGcwcHvkWOKpXuiqLiPjI3XIZJBv91lub59CORWBVAysmDKyQ8QgsQGSNsakaUhAYIAPqlE+hgHpRVeMB730IFcfOK8RbSVPHTghZCsn8IJI0hk/fA8WYXYuhovfVa8O3eudy69eWLzjsP87NXm7dXzbA6oXfnJNBflwaM+4uJrpgt6/fTlFwC+dyY7w1Fvk8KAwYHChHRsQGAVvrEBgSsGE2DtYATAwFE4MBQAUCgkBU4D3EewtRD3WK1FmkzsE7gstI00zQaoEynyFNNkucLCZg+q6lUpVLRoYGj1KWv53wla+sfjn1f1kA+750wblBYGcXunpOJcUBu3zrsIbBryhfnGaiyEghIoSRahiAcgEjyCkCqxwEFsY4BCHBEAnIIzAEsGEGRDVgYgXUiQAMcfAeEDXwqshSFe8t0syxcyRZTIgz0TSDacYkaapoNb2kySaK07MAVEaLqIRnGkNDv3ferR7/rxdd+ZoC1Asv5L6R+k9yudJTuXz+YgA7O3EOwquQjyoo5POI8oRCBC7m1YcRKIgIUUgcRSqhVUSRARtvrGEPkiRuVBsDw83B3m3Ot2KqDQ8TAJR7utXkcjpm4qSgOK4nn88XK1BlOC8iziBOPWeOkCTkk0SROqU0Jm00QEkKtFqqzVZLG406vHxol6q4pNn6XBw3jh23Zf3ZdN11/lUHuPpzn4t6Mr2h3DX2T8T85eeoYjuKuT9QobwPFfPQYp4oX4Tmc0AxD+RyanIBxIZk8hE8sx3cuLnv4ZtubD774MOz01bzQI4KjwTdXRt57NhhDYO00FXOAKA5UgsozUIZGOjOhkemSdI8NMwXnt7vsIVrDl20uDhu2tRxRtT5OCZOUvFJqhTHhFYMbbSIkpai3oSvN0Ct1lY0mqeAMHFn0UUuqo0MHDkU0Kn7X3FF8qoBXL34c1HXxNYNlZ5xawj0qZ03DN3I5UqMYqFgSiX4UhEo5IkKBUUhDxTy4FweEobF4R19g7f+6D8a29etPz6cPPGWniOOHM5Nn1qKyuUKk+UgCMSwigoLMwQARNr9ocucEUC9TzWu1WqNDRvrw8sf6HHbd7xz0uxZd5z0iY+VK+Mm9HCa1aXZJG01iZJYfbVJHDfV1BvwtQbQbDSlVsvB6+JdQHxvZLDvwDq5d8/86U/jVxygfu5zUV//4I1dXeN7QXTWzvdN+GNTKU5DpSJUKYKLRaBShi8UCaWCUr4Ijuy4NY8/9syNP/rPg6mYf3bSu9+zpTJj3/FhaG0YRWRsiCC0yFkLgAWgzFgSMkYBQL0n74iZJRDxnDiHLM3Ue4eklVCaZVlt3fr+3j/8YYrWG7NOOfeTT86cP+8AybIdaLRI63Uy9ZZKowodqZOv10G1WiLVxiD77CO7VPPqkaG+aSMjAyfvf+ONL0kTXxLAa9//fvN2p7+rlMdsYDbn7oQXhj+kSnkmd5cJlS5QpSwoly2KBUGpRFTIj92+YcP663/4g/2CSZMfnnrG6T6sdHUXopByuYKGoaEwDBGEIaIwJGOMhGHovKfEGPVBEGUAkGVJoEqGCGGaJoH3npPUiXcpxXGKJEmRpC3EcapxbWR463X/bZLebQvf95nPrpm4777TpNUYQD1WrtWdr9dCDI8IqjVItcpUra3WNPvMzjqpfH9kZOCACQGd/FL6xD8LUAHaccq7flEuj9/ARP+480YuvIzK3fO4uyzo6iLT1QXpKkMrZZhSyWTQiddd/r1n62lMsz/+sb6ouzKmmC+gWCxImMtTFAQmn89REEQuzIXKABtjhIgUAAPIOgkAAnQMlarCe8+i6tMkYeecbSapxs2WZGmszWaCRquOWt/g0Iaf/WxiJcxl7//8Z+ayoldrdaFaXTEyDD9cI1NtiBseUNtobHDN+FPP1Vkuqg4Pzph40w1nv2yAW4874dxKqZyzJnfZ6Hucz31fyuX9TM9YoKdC6KkIlbuYuyuiheLEbZu3rL3h5z87aNJp77lp7PyDpuZLZZTyEQqFvBaLRQRRzufzeVimoANsAMB2AFsAbAbQByDZDWAEYAKAKQD2ATAZwBhVhXMuSZ3nZrNhm/U6teIUraSl1ZGGDj3xWO/263+76D0f/chjEydPmaWN+nYdqTKGa0B1WGRomDA8QjpYfRZZ/HejdXRZfF6tWfeT77rte381wIHD3zpfQ/s3xfKYL0GVAQA2+iF3lWfpuDFK3V2Erh6Ysd2qlRJToTD3jzffcseza9dMm/s/P7clX6wUKpU8R/mCVkpFLRSKEgTWWmstgEEATwNYC6Cxh3IJgKM6fy9HWyu1c4861wUAswDMA9DtvXdpmvp6vW6arVQazRparRZqQ0Mjq//9+/vvt/9+a4898Z3v0Li1CsNV9cNVz4ODVoeqIsNDHsNDG5G5tiaqukZ96JLM61WT77/nqb8Y4JPz54djw8LN3eVxUxS6PwCA7a+op9JF3V3MEyYQuiqCMV2M7m4gCg/6f7/573uauUJj9t+eXSiXyzaXK3JXuaiFQh6FQsExcxnAJgDPoK1xhHbTpA6g7g6UgwAcDmB2pzhrANwP4KkO7CoA34HoOq9jOp/b13ufJEmi9XpDq9Um4rhOtVrVr/np1Y1CKy68532nH0NZ+gQGhtQPjxCGhlX7Bw2GB70OD4/A65JOvqtGagPbJrK8kx56aI/TPrM3gF8ZO/HfugpdG9W5U+EcyPmnqFioarEYULkCKhWEymVGpUxgc9A11123ws7cb+P+HzprXHdPt+0qV1y5VOCuroqGYRgZYzIADwJ4Fu2mWQHQIyIREUUAciJCRJSo6qeI6NsA7gZwO4ClqvppIrqpU7xIRPJElAfQg/YSWQJgG4AhZh5rrc1HUZgGATMRGRuGKM87yA5v2Tz02N33NOfPPeBQUfSyS1nTDEidauqIUie+Uffk3AQ4NzYy9prBZv307/bt+N1LBrh1zpwDQoTTAzIXtKdO4jSMbuJysULlippKCShXiIolImsPuf6m3y+LDpy7ZeYZp0+qlMvc091FpVJJy+UyBUFQYeanADwCIBWRkIjGiMg+qjqWmaep6nxVPY2IjlLVJ4joMACnAzihkxYR0TCAR1T1M6r6FiIqEVFFRHKqWlFVUlUhohjAWiLKjDEzoyhyxhhlMrCWbGn//UrVoaG1Ty9dGs+fvf+bSWgL0tSqy0BxBmSppSx7FnE8H84zvBzjnLvhf47r2XZpf//AnwWoAFXHTfivclSeR0RTAYA4uJIqpamolJkrJUi5ApTLxLlw9u0P3HdPOnnS0KwzzpjQVSlTsVhAuVxGoVAoMHMOwOMiMkBEkYgAABMRqSqJSAqgn5mfVtVFALYC+Bu0jchVAG4AcAeAJ1R1tqq+T1WfJaJ9mPknABqq6gDEABLvPYjIEFFJRFJVbTDz5CAIDDO1mNmoshRnzOgeWr9+oPfZZ9fOnDr1MFHpJ+cUzqv6lJH5IpL0VqgcAQChCcstFy+6ZKD/Z1/7cwA/PWfeCcWwMMhsP94mqiu4XAJVykzlElG5i6irCCrku9f2bnnk2aGB8rxzz43KlQrKpSKVyxUtFAqWiLyIPKWqCYBJqlpBu5/qEZGJzDybiN6jqkd77+8hoveq6nYi+g4RBar6QQDvBPAOAAuY+W4APyKiBao6A8AtqvpFAAtFBERUZOYKgPGqWlTVHiIa6qRyEAR5a61T9T4IIi4fOCdcd+/SfJGwprvctQ9EEnZi1XmFc6Qu60Ka1gGaDMI+AfFlQ2PG5i7p37F+V168u/YJ9KvWRl/a+UCY+xNyUai5HFMxUuSNIoyQthK6f+XKhQed9/fVUqlIpWKBS6WSz+dzQfurcC+AQe99WVXzqtqtqhNVNSKizap6u4iUVLVFRBc5574IYI6IXOK9f5+qiog8IyLPqKp4798nIpeKyH6qer6IfNN73xCRCjPfCmCt954BdAHoIiIjIkUR6RORZUSURVFki8VykM9HWiyW+KC//3zz/pXPLEySRCm0RiIryAVKuZyafJ45Ch4Y5WBN9EURf7HuZnifp4F/N3f+WwthfoTJvL/9Dt2ihahiKmVoscDIFxWFAlEQzvvtI38anvPpTy/vmjC+p1AqoburolEUBUQ01Tl3D9rW1DNzQ1VrzJyo6j4AFgFYSERLVfXdAC4HsICI3gvgSWPM94joZhFZq6pxpznfraq/Nsb8UUT2AfBhZh4G8FMAxxPRLar6BQBv8t73qeomADuYuQmARKSMdvew0FrTMIYVRAAQFvaf89T9N/x26gGTpkwn7/uQesCnUPHkY99NLlkNYH8AFct6SX+lB5cO9m/eCXZXgF79N4wJp47uvpgo2CxhYYoEgSIMlYKANLB2Ze+W28v7z0m7pk6elM/nUCzkuT20w1Tv/UYAbxWRhqqOrnhscs6tIqJbARyvqomq/j0R3QbgAiK6Q1VvJqKzvPcXqT5//2f0b+89ADxijPmi9/5dAL5MRLc4584H4IkoJKKbiWiMqh4gIlNUNWDmfhExxpgtzDwlDMMtBRHyzvvuqVPGl/af9ejqbVvs3DFjp0kQOAojFROQKQQqLtymSdrmwflPESenAjjxBQDXzZ8/iV1wO4CLAEAJd4kNpyCygAmI2KgGBkjdlCd3bJ+54NOfWFbI5xFFEedzOW+M6QFwFxFtUdXAew9jTMV7fygzv5uZ6977bxNRwXt/gTHmUlV1InIBM38VwDs6oG4RkbuJqLkbxAIRHUdEJzrnDgUQM/OXReQTAKZ0NPBSImIAnwJQAnAnET3mnBs0xkBVM2aeYK09wlo7kM/nDaA44MNnRw9dePFb9ytVMmbaAGtgQqPehIAJ9oFmfwTp20E4gNn+cu3MgybOWvfE9ucBDBJ5X7EY7dynZWOfhjEzjbWkAUOJiRRmxY5t901bfHItly9MyefzUiwW1Vo7SVV3OOcWoz2wtcaYDQBWiMidRHSqqm4jog+LyBZm/i4RnSci3yaii1T1Hmb+tff+QACnEdFJ2E2ICKq6XVWvVNWVzPw/vPff7IA8T1UvFZFNxpgPi8gIgAnOuduDIOgGcKyq7uu9Z+993Vq7PYqifYhou4jXLPOFKSce9/tH7vtTeUHPuGlK7MFWOTAiQQAT8FPe+bcDQCksjvVu5HQAPwQ6RkQB8mtXTwf47e3GQn1gM1WtgbckwqywRN6l4zYn8dsnvfWt46PQahAEFIYhq2rivV8G4Ceq+v9UdbWInOyc+4S1FqoKVf2Bqh6qqr8RkW3e+8tU9XYi+rKqHui9vwzAuWhb6UcA/MY5d7lz7nIAv0F7HNkD4FwiulRV91fVL3vv7/TeXyYiW4jotyJyqKr+H1UFM5Nz7hNEtNg5t0lE7iKiX6vqnUQUW2tNEIQU5iLd9x3vGLclTY7zWdoDqLbrzGBr4GH3VcWAAgDTcbJ29b6jP6xBW99nGJOfEYy0ijSmO1TCLRREPchFZIKANQyFQqPPpunq8C1HPjl+3oHlKMpRsVgQZj5AVR/z3p/V0egBVV0JYDEzbxORfQGMVdXDAPyaiD6JtrH4oYh8TFVPQnscdzkz/5f3fnVnnDiLiBYR0WGqKqq6XkRuNcb8ynv/eGew/W4imi4iXyGiyQBOZ+afiMhH2nqBsdQ2FhONMVeKSAzgMBF5LxGtYOZDiagPquS8mrReWxFv3jw4hrlIaQpJM1LvGN4ZdemDrDRG1qx9VLys+TvJNl8OjFgASGBO6Db58ar+fbxu3dUye78WDBMRVNgAAguHYJ1Lj15w8onLC4UchWGo1tqIiLap6urO2OwMVd3CzFd0xmY/VtVvA/gCgEtFZDERfUlVv+WcewuAW4wxfxCRt6vqlzpGAp0BN9BeUACAQzoJncEyVPW/jTF3O+feTUTfVFUB8CXn3BeIaKL3/nxmvkRV/5GIvq2qARF9QlWnA1gqImuMMbOCIAicc1k+r5h16ruKDz348JGzDe0gIAUzQExEVmBMitVr7obXsyObW5e6+O2Av5oAYC3s78YVxhypinEA1blS/i3PmlnWUtFSPgcuFCjOBc3l3RXz5i9/MQnDkHO5HIVheLCI3P6Nb3xDly9ffg4zR7v3XW8kEZHklFNOuf9jH/vY74IgKFhrJwE40Tn3aJIk2opjevDib+WPGm6lhTTNS6OpiJvQetPrug01P1x9L0ELRNgx0By4byb8aVYBXg+qimIcACj0FsTJOOzojbk40wMSiM90HezwtFNOrhtjJodhKNZaUtVCkiSz7r///hOZmc4888w/rl69etWcOXPmPP300ysPPPDAuc1ms56maQag55ZbbjnOWrvitNNOG2Fuj+H7+vr6+/v7ByZOnDh+zJgxY6655pr5ItKzZMmSezvN73lCRHj00Ucbq1ateteYMWP+dMIJJzQ6cPSZZ55Zvd9++80IwzAcHBwcuPnmm0+w1naXy+XbFy1aZP7whz/ozTfffHylUnnmrLPOeluWZZuCIMgZY5SIyDBj2knvfHbDdb8pz3U+r+otvCayfYeXZnOcQm8BcJoqJgCcKDzbTcCknA0fBnAWAKjyDiWUtZmEfv2mxM6a2VAbdG8L7SGHHzTv0SAIgPZofJyqPtJsNt9sjDFZlsVnnnnmMara6PR3C4noJ6p6HoCHmfmmW2+99bh3v/vdI2ecccYQgGUAzgZw3C7jvjU33HDDxlqtFpx55pk3ABhdUg+89wUAMwGcsHjx4uI555yDM844Izn++OMLAK7z3h9rjPlkB/JFInLm0qVL++I47r7iiisOyOVy5dNPP33pOeecs/K66657z5IlS54mopNV9XcAxllr+7xX2ufNC4sPXH/DvLnS6JPEx1i/UaXZKrR/S9422qtYGz603mUT2AP7Rhxyu89VcOADYnWqHuLSfLpxY5dWa9vZmO6wUCiTseC2+swTkY2jlSciiMjFqvouEbkEQE5VP6mq56vqId77LwPAtm3btqnqqar6HRGZB+BqEfmCiFykqqvCMDRERM65S5xzl3XSd1T1a6p6uqo+2Gw2vwcAvb29G0XkMFX9DjOfDOA7AH6mqhcQ0aw0TT0AhGHYA+A7RLT4Ax/4wB1ENHnDhg23qSpEZDOAedZaMobI5HIltcF4DNd28IZ1OfGuCCiUycP4YJRTyCEE2Jc9zFwY3rf9NqDe9DjhQAUW3oNcipH+HcmEgw/5PhEnDIWIKIC6qtZ362POArCUiP5FRL6lqjVVvURVfy4iPwKAKVOmTAbwsHPuCwB+5Jx7P4BLAVwgIouZmbQtN4jIr0TkV97721T1MREpiMj7SqXS5wGgp6dnkohc2fkBnhKRL3Ys8JUicl0QBKYzhLpMVb8BYOlJJ530NhHxt9xyyzGde0NEVG3rAKVgbk6cP/97IwPb1WWO4T2p91aFAxUaM8rJGp4CmDkWoDcTuON+RqmSlgyJI/Uq3nhKM9SisKX5cJYxrNbamjFmnKpuc869s6+v72cA/rGjhXMAbPbe30ZE/wLgHhG5jog+O6qp69atWy8i7ySiSzuWelhVrxeRx4wxSaPR+EC7K9GZqlrsXO9Q1Q1EdIeIbKnVagDwHVUlAJ9WVRDRJufcBcaYA7335xIRvPerOv3ol9FeFgPaq9a9jz766CTv/XcALGLm7QBCIhokIOJibkY1CJs5X/fshYyqcyQGRBEpUkBDEM0jaGYB7KekC6EEgj7JAOC9aHvnQSAW/cVSuO/cuYn3PmLmnDEm7UzDFlQqlb4OvGDZsmXfO+yww86x1m7z3v8LM39NVd/mvf9+54f77OzZs2eoatF7/x1rba+IHAngFAAf8N6jWCw+2mq1SER29SmcucvQBsVisQ4AW7du3UxE56vqJBE5tzOrEefcZStXruQ0TT/IzGi1Wl/P5/N/Q0SzmfkrY8eOPaO3t3ccgGNEZIGq3sXMKRH1QFXGzp2bbSyWypPTXqgXdd6BvRdVZEr6FBSHMnCYgBMLIA+lCgAo6RZRhFAFeQ8IQSwQR2FPYZ9JW4MgSK21LCJzRaRJRB81xnwNAIwx5oorrvhspynPEpF/BlC11jaiKDoZnd73+uuvn7Fp06bHrLVHhGGo3d3dEJGHsizbGsfxjoGBgTMBFK6//vqrjTFBtVottVqtuNFooL+/X7Msc0NDQ1MBvO3WW289aenSpUfEcVzy3ouIxEQUGmPOA4BRS++c+6SIVIwx53nvL91vv/3uXb58+SwAE4jooyJyjqrOtNauIiJXnLoPJ8Woy2cZwYuyqIoqoEgFWMvAoarUDaBgAfCo96sqWiA15L1CmMApICDJh/l8qcTGGFFVj/aUaqRYLP7L2rVrf9xoNL5eLBZ3aggzEzOHaO9VVJLkuU1+7/2MBx54YAb2Isa0V9h+85vf/Pk9WaKJrVZr4iisUWC7y9q1a389b968aQAuA/CMtfapOI4XeO8vLpfLX4vjeA3aa4gCQE0QqURRDmlKgEK8AAqCihK0iueGV8yA2tGOkYAUIIEoqfckzpPLHBAEFY4iEhFnjPGqOhbt3bGZ++6778l9fX3YsmUL6vX6zqWnN5JYa49g5lNV9d9E5FvHHnss+vr6cpVK5X0AphNRA8BY770AEJsLSYytqMtUUwd4bbMDRBWNUV6AWn6e87WSV9KmGtRhUGdwPYCpE1srzmVE1ErTNFHVLd77AQAwxswEgCzL0N/fj82bN2NwcBBZ9rKdP18xWbVq1ZPe+49nWXam9/4/DzzwwGcBpNu2bTMA0FmE3UpELWNM3RiTsA1CgOpgqpNBnRk1z9QU2J28aFT7dr5BmldFyQIqIPKq5OFh4evqfaiq+c48dC6AjXsqrPce1WoV1WoVYRiiVCqhUCigs+D6mkmWZWg2m2g0Grjqqqui7du3Hzt58uTbJk6cuHb27NnvJ6Kt995779NLlix5E4CJqjqHmR8CYLMkSQP4qgrKBJAwhKBgJVZyFjs9jwEreE4FhajIopRAGSAGkRG1CJwfcnEqlMtZIhIiqhNRcc9Ff07SNMXg4CAGBwcRBAHy7QVYRFH0igN1ziFJEsRxjDiOn9cCduzYcdbVV1/9gs/84Ac/WLFkyRKoahlA3XtPzjmbtVrMiWs66BgQiIWcQpVZQwJ17eQFwBLQC9UNIEyHoqJGYwhIIO21QvbepGktHhpyQXeFOyvNDeCFHvi7yBAzb+zkwSIyLcuynl0rZa1FEASw1iIMQ1hrwcyw1oKInmcQRGR0TREiAuccsiyDcw7OOaRpOrrcvyfZxMyD1PbBgfd+Ptq+NhgYGDgJAIhoHwB1dFQrHhlxuSyteUg3g4xv93VKYFJomaCA0hoCtliBPi4EQ8B0IZ1LgscZUKfwgIoQo7S9v9nYtDGMpkwxYWhtZ2B7SCfT5wkRPU5ErqenZ924ceNkx44dPDIyAgCbReTg0edGK/8qihhj/qSqZuLEiWvL5TJv3ry5GMexV9UxqjoTQNrb27u8VCq9mYgeFxEbxzE11m8Mcn39Dc8QFaiFAkSkKoZID1YlgOQhQB9lBT2tKqsAgBTjhaTmSb0C6kDGiQa8dWuhsWZ9TtVb55wBMKiqxjl3LwCUSqXfjsJj5vqiRYsmBEFwOjOfEUXR6SeeeOJYImow85OvJrFdxRhzfxRFQ0cfffR8a+2ZQRCc0dPTs3jx4sVpZ+q2paen596VK1c+pqoBgMHMeyYiaqxdVwy2bCtnQoEA5Nu+TJ6gI6o0BgC86rMCeoYZfnXm0+0Ytc3CDXiygASqYK9MNFwrNNavnZ2mKURERaQOAEmSbN1t2GIXL148pq+vb8p3v/tdiAi+/e1vo6+vb+qJJ57YjfbK81/syP1XyAZVjRYsWHDc2LFj81//+tcxffp0nHfeeXjyySffsmDBgg3MvKNer49LkiTqdA11FYFzHsn6TbN4qJYnBYmCFQjEU6BKzVFO4tMdgF9rCVib+Oy00OQAAMTUVFEVpUyhUKhFko5F4g5Mk+QOIgqIKGVmOOemX3vttXfW6/XjrLX3EpE89dRTxy5cuBDLly/HvHnz8MADD2D69Ol45JFHDmDmewE8rKrjXk16RDQwadKktRs2bFgYRRFWrVqFSqWCe+65B4cffjhardaihx9+eG2WZVOMMRYARCTN0hQuzRLN0nk+i58ASAOwCOANgcHaVGlb4KbPxjtgjd0fqK4Uf/ROWyxqASYlsVBWBbwCCPv778x6dwzQPvtMMsZoEASbVfVtRx111E3PPPPMzQBwyCGHFK666iocwXXn3QAAEZlJREFUe+yxePbZZ1GtVjF16lQcc8wxWLp0KRYtWrT60Ucf3Wl+X6lB954WXk866aSJy5Ytwwc/+EHcfPPNGBkZwTve8Q40Gg0sXbo0nD9//vJWq8UzZsw4RUQ2dgyVtjZtGgj6+m9X8EQAQlBWKBFYSBBqh1Mq/m3zgQvabrNAnwIPEHAEgBMIspJUIKTkARaFMQ89OlJbvjw/5vTT1DlHxpgnACyaNm1a38UXX/wxEYGI4IEHHsD111+PJUuWgJlxyCGH4Oqrr8acOXPwmc985m9Hnxu1qLta11Ggu7+OAtr1lZlBRM+7Hp3OjVrwG2+8Eddccw3OO+883HXXXRgYGMD999+PBQsW4Oyzz/5okiT/KSLjVPVGL6KNRoOaD64o24cfq3nIFEOkAlIDdYAnAb+jw+sBAtYBnV25v4OphWyHmPidALqgtEIIxbbnIkOg5KrDJT3ggLebgw9ew4aNtTYlonne+2IQBN2qyiKCOXPm4Je//CVEBKtWrUJvby9WrFiB888/H8Vi8Xnw9gZy1793T3vT3t21kIgwefJk3HzzzajX69iwYQN27NiB7du344tf/CKstS5JkhKAsSKyIm61qNVspcnd95yst92RWMAYYjEABYCxsIMKfQsAOPGXpz77w/cg6xkAArj7W65VHs1cGNsZpBYMQKAgiFIevX23tTas64vjmFqtFlT1QQBzkyT5xWgFp0yZgiuuuAJRFIGIEEURLrnkEkyePPkFkF4see+fl17KZ3aHfdRRR+GrX/0qms0m0jTF3LlzcfnllyMMQ2RZ9gtVnauqf0rTVFutBK11m/pNb98tqhIqoKTC3LbAqup3jPJpuVaXh/sTsIun0dMwf+zJd+0PxWRVPA7CjhSglgIJhDxAaSm/OffZT0+17z+9t1AscqlYZCI6Q1WfiaJoWmfF+AUV/nMAdtfCF2vCL9Zsd0/GmL39PRTH8QARzfYi1zXqdbRaseh//fe41uXf326ayZQA0BwMAlLJA8SKsUp4EwhbBlsjz86DPw7Yxb1NgEuc91e0C4qDFboDECK0zY4KyNdbU2iknqT9/X1JHEur1VIRuU9VD0iS5Jo9NbndwewN3p408M/9AHv7vr3lPZriOL5BVfcDsCxNErRaLcRbt/XpSD1zzXiSgtgAyvAwbSPSq4Q3AYB6fzmA/z3KbSfAEP7melqfNrppQqKtAIAhUAiAWD1BbO2XvxyJ7l52QL1eR6vVEieySVWr3vszvff37K3v2luF9tZ0X+z6xZrti/Wfqoosy2713p9FRMNpmm6u1eucpqkU7n/wwPov/m+DAGsgQgAZAhkoWDQZ5TKY1ueuh7/9BQD3BxLfNtHXdHxAPgyiEduZzzJAEFI3PDxO+3aMYP3GvlqtybWRKrz3d6hqMcuyblUdGm1+e6vYi/V7f8n13mDuCWKnTL1pmk4CEKRpeme90aBGKxa/ZsN237d9OKnWxrQdKEm4c9qbCcPKdLa2rcEvAG2c0nZofz7AdjOWC0fSxuiZCMuCHQYg204IIEoA9f7kqlLlqZXvTONGrd5ool6vp9r2OD04juO7te3L8qKa8FIMyksxIC81H1WNW63WU0R0sIjcFsdxVq/VEdfr9a6nn17c95OfFRhCFkohFBZqLKAQ7kfHi62aNtcmkG/syux5AA8GtntxBwB0BwAo0YcD5WFDpAYEA4YBQzPXvf26/75vzP0PlhuNmtZqDWo2m4MAHgLw3iRJfrWrEdj19aU06d0t8K4gX8p37CnvJEl+h7YP4oOtOB6oVqtaq9do3EMrituvuW4ZMt8TgikAwxBgicDKwyD9CAAocIsTN3th22N2zwABIIb8r6G0vqzd4jUnLD4E1HS2OgJAQ6KkuXrlfn79Rp9fs663Xq9ptVbzjUZjjao+AuCDzrlfAHhFNPFlal6aJMkvVfUMAA83m821tWrVjNTqlHt27WbevJmba9bMMgRvALWAsBIFgIA1BRAqgKG08TBBzt+d1wsALgS2irhAIT8CFFCcYYFVAUHzgIYAWRKyUF37o590j9u89ah0247eWrXKw8MjaLZaq1V1uYj8TZZlN6jqyN60cW9a+WLjwJeibaOvALamaXoPgLMUWN5KkjXDw8M0ODSk0rejf0LvjiPX/OA/ihaAhUoHIIekxJCVpLqkzUB+KOLsfOAFUZH2eNDmQ9ClcG5J3uZmKBBCKWcNDQsQCEQ8wSiIRMT0Llvef9CCQxZsjIKnHbikIgKgGQTBJlU9xTm3GsBqANN2b3Z7et2TMdh1/Lf7GHBPY0IigjHmHu89EdERAG6O47hvcGjI1OtNifsHBg5cv/HYJy765gbrfaVAxCGBilDNEWyOTaxCbwJhHIGqQ0ltex/kcz9re9/+eYA/BtynYaqG6HHDZhEIE6D6EClXAHgHYgAsBPLqo833P7Bm4cELjt1A9GhGWnaqEOdbzPS0MWauiExX1Z9re+Qf7KkP2xO43QHuCmhP0Dpz4CERuVZVTyYicc7dPlStJrWRmtZrVY37h/oXbu094bFvfXuFSZOxEZGNFDYCfA6MHDGp6nYiHA8Aqc++lIn//RGQPUb32OtZuR9C1nxc/GcjGz5JoIMBmk+svyPQBAACUqiSVVJIlhW3LLt/5eGHLzx8o8NTKUkh88555wNAN1pr+1T1VBFZx8w3icjB2j6a9bwmt2uzHJU9QdqLBgoz/1xVJxDRUQD+2Izj1fVaLalXq+FwraZZ//DWI/r7j3/4m998gprNSTkgyIE4YmgBLDkiWKUniXAOAAjwi2ra2Ocg+Ev3xmmvAAHgH6A31lz6oZzJEYCxUD6YCHczoUeU2DMMQCBSylzWtfHOu2tHHnXk9DjLHu/1bqzKzj4sZrarARUROUnbHq2/Q9tFrmtXiKPXe1p5GZ2K7QZvC4D/ApADcDSAJ0RkRa1Wy2rVBtXqVQwODMvkoZGtbxoZPuyBr3ytj5JkfJ5gQmWTJ0IR7AsEWKb1qvhIh8uq4WSkVYJ+6N/30HRfEsB/B9zHgWVO3fjIBAsIGhHRDIY+xNAygRVQgjBDlcW7YN0dd2bzDj7YTjXWPJVltVbqOUvTXOYz8c63VGU1M9cBHKKqU1T1NgB3S9uzfho68/Pdm+0uyRHR3UR0B4DtRHQgM5dUdV2apk83m83myMgI1RpNHR4aMLVavX5stV6sbNpaWP71i4qBl2IEaF6ZCyxSAEsemgXEW1RwGkGLANxI1riaVL4yp30YfK/ykmImPApzap7t3EKQ+067ctigwP2xYlwq4AYLN6AcgzQW9S0oeubM2fTmv/v0kY8Q3bUxF3bnCpHJBYFEUZ7CMEQYtnfjmDnsaOE07/047/16Vd3S8RZIvPdgZgugQkSTmHm6MWaYiDZ2oKejO3Rx6rXValAaJ9qMWzohTre9FXTy4z//5dLtDz64fx7gHLdHE3kYXxDhHINyxFsVeCsU+wKQetb6p1T844fA3/jn2LzkqB2PAOeUOSqHQefoP2EThP6YkUxvgnwLoi2QT1RLTZUkUTXehukxXzp/MJw8acyt3j1RZTOhkM/bMBeQNYHmcyEAAxMwhUEgaLurdcJmAUTtU/LS9kfU9jUABrIkJS8eBGiSJJRlmaZpqtV6S3oEAydZO6+1bVvfsv99yVjj0jBH5AsgHzKFecAVwFIAyCi2EeMoKGYBQJrF5zUlSQ4G/s9L4fIXxY15BPhqV5AfsRx2INIQAdd7yP4tQJseQQvQJpRarC4VlRQQU+5qHP2Fz6e5CRPG3dGsr9geBOMtIQzDnLBlCkyAIGBSJTWGoKoZGePEOQ8AbK1R7y0RWSfKDEWaeiiJpnEK5zJkzmfjVftOyOXfnG7v237vv12Wk1qtEAKImGxOyOZBvgClvAHyIDWglar0PwjtfjiV9Lx61iq8CfjWS2XyF0cuegz4+zyHYRTkvwmAFUiJ8WNRPTSGaqzwTYEkDI2hpuVhHSFLoGq7K4NHfvQjtfEHHHj8mlZ828NJq9HnsnHGhNYGhgwD1rYNhaq6dgwZoDM5sCKs4jLy4uEyp+KzrDsIB95aKJSmBdEJ2598+s4HfvaziqtWe3IgChQ2b8hHUJ8TQp5h8gREIEtKjwP4KLU9yKSZxV9IJPmL4P1VAAHgUeAjAduppaD0v9CJd2oIvxKlcgJfjAHTFLIxqcaKLGXlTGBa0CxTsWK40TNjZt9hH1hiumfMeEcs+sS6VmP1hjh221KniXrK4I2gHXiH4cnA+DwZnRQEPCOfs7ML+f0j4gMH1qy/88Hrfikj69aPZ9FijthZUBAxfCQkOYYtClHI6nNgH4AalrThFWd2CAwOp41/F3FrDwV+/pey+Kujtz0EHMXgT48NS3NBGI0XuAqge5TkgFhJEqiPgSCBaiJwKSRogbxTNY7IZ6rGkWYmFw10T506MnXBm3X89Olhvru7GJXLlSCKxgNAliR9rWp1JBkZafZt2JBufPghHtmyuUviZEygFAREYlXZErkIGoTgNMewEYhCIMsBlCMERvkpJX07FPsDACnuG0rrazzk8gXAn/4aDi8r/N2TwJgU+HlPWHqQiL/y3B39NROJE0yJiVwM0VQ0TIE0ZVgH+EzEZKAsgwYegIdmClivnCl5B2KFSHv8xWyhQlBjLElIgCOQDUFqAR9AA8vsQ4ADgc8BgWVKc2DOqQbM2KSqAYHeN1pCUflaNa0fTsCHDgGG/loGLzsA47WA2Q/4Z8sWXUHhQ9o+nAwFUkB/ysAYrzQ1IU0cqYmVxAGcifoU4IwhHmIgTI4FIuQEUAWI2lNGKFQIHZcxVmuElVgQgL0RmBDwAZOxgIQEEylcpBQxY6MRJI4weo4PAJ5pZM1rMnHuTcA36bnjZH+VvGIxVB8HZjvghyVbvCkw9hsKLXRuCSn+rzIEqtMzgnEKTQnkPJwzCJwCHuqkbTUcAeIERNSeAajCWoZqe2XcctuqBJahgUdmGUEAeEswgcIR0XoVWGqD43ZFqZn49CtN11rkgE8d3g7487LlFQ1CqwCtgDmVIH9bDIsPWeJ/1vYUa/T+kwq9j5WKRDQ5UwmFkHmAPRSOQOpJhSHtlcT2fI6gCiYigWGjsAplkBoAAWAMOBPVbSBtEOhotCMZjVYwdioXN9LGmwX844Xwv38lQyK/KmGQHwQCMmYJRD6UM7nbQms+D6V9n/cQ6VYAdwLUIiBSRQVAt5IaArwHgbQ9jFESNu1ItKbtLIFhIlQ73UQOwAlQmrRbzTaIc5c3fHyiMv9Cvb/2sOdicb1i8qpGMleAH7T2BPL6T9aYu3Im7CHQeXsvDQ1CZQVAI6QY0fZ0DqRaVEIXoF0gXgDVMXv7CoVeFvt0KPP+WGPoWwucu/Pl9nMvJq9ZLP0HgXFg89U8h+uZ7SWvRh4i7vyGZNNZ3DcOA171MPDAawhwNL8/sfllzuQ2M/EL9hdejojq5bFrTT1M/RmvVtj3Pclr/t8c7gRswdjfFzjHoOfCh7wcIcU9dYlj6927Xo1+7sVkz0d7XkU5HnDq3ftjadWVdNPOU6J/bSLd1pBWb+bdktcaHvA6AASAo4Bq5s1Xmz79tQKpoN3L/6XJAy7x2VXkzdfe9jJmEy9HXheAAHA00sdJ6QFR/Ye/FmCq+g9edeURSF8z5/Xd5TXvA3eXZRxcam00zMDukeX+nHwj88nYt/jnIvC+HvK6A1SA7jPhb4wJqtSOofBS5NpMsuKtLn3Pha/iGO+lyOsOEACWAXm1we+Ywm4iLPwzjz/mJNuSufT049vHJl5Xed36wF3laKClLjhbJHtEQdW9Gw2qZ97f5505940AD3iDaOCo3GNzx4HxVlZz0Z7ui8o/KrLlxzr3x9e6bHuTN4QGjsrbXHwXRJywnP8C7WP5AkHkjQQPeINpYEfoHpP7hRrapEr/0H5LL2fR8W/z8d/gNZymvRR5IwLEnYBlW/i9gJiACNBYXfOU41/ExeL1kjdUEx6V4wEnLlxCkCogfeqaZ74R4b3h5d6wNP/esDT/9S7Hi8n/B3LrBEUxxEM2AAAAAElFTkSuQmCC\"],\"useMarkerImageFunction\":true,\"colorFunction\":\"var speed = dsData[dsIndex]['Speed'];\\nif (typeof speed !== undefined) {\\n var percent = (speed - 45)/85;\\n if (percent < 0.5) {\\n percent *=2*100; \\n return tinycolor.mix('green', 'yellow', amount = percent).toHexString();\\n } else {\\n percent = (percent - 0.5)*2*100;\\n return tinycolor.mix('yellow', 'red', amount = percent).toHexString();\\n }\\n}\",\"markerImageFunction\":\"var speed = dsData[dsIndex]['Speed'];\\nvar res = {\\n url: images[0],\\n size: 55\\n};\\nif (typeof speed !== undefined) {\\n var percent = (speed - 45)/85;\\n var index = Math.min(2, Math.floor(3 * percent));\\n res.url = images[index];\\n}\\nreturn res;\",\"strokeWeight\":4,\"strokeOpacity\":0.65,\"color\":\"#1976d2\",\"showTooltip\":true,\"autocloseTooltip\":true,\"labelFunction\":\"var vehicleType = dsData[dsIndex]['vehicleType'];\\r\\nif (typeof vehicleType !== undefined) {\\r\\n if (vehicleType == \\\"bus\\\") {\\r\\n return 'Bus: ${entityName}';\\r\\n } else if (vehicleType == \\\"car\\\") {\\r\\n return 'Car: ${entityName}';\\r\\n }\\r\\n}\",\"tooltipFunction\":\"var vehicleType = dsData[dsIndex]['vehicleType'];\\r\\nif (typeof vehicleType !== undefined) {\\r\\n if (vehicleType == \\\"bus\\\") {\\r\\n return 'Bus: ${entityName}
        Bus route: ${busRoute}
        ';\\r\\n } else if (vehicleType == \\\"car\\\") {\\r\\n return 'Car: ${entityName}
        Current destination: ${destination}
        ';\\r\\n }\\r\\n}\",\"provider\":\"google-map\",\"defaultCenterPosition\":\"0,0\",\"showTooltipAction\":\"click\"},\"title\":\"Route Map\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{}}" @@ -72,7 +72,7 @@ "resources": [], "templateHtml": "", "templateCss": ".leaflet-zoom-box {\n\tz-index: 9;\n}\n\n.leaflet-pane { z-index: 4; }\n\n.leaflet-tile-pane { z-index: 2; }\n.leaflet-overlay-pane { z-index: 4; }\n.leaflet-shadow-pane { z-index: 5; }\n.leaflet-marker-pane { z-index: 6; }\n.leaflet-tooltip-pane { z-index: 7; }\n.leaflet-popup-pane { z-index: 8; }\n\n.leaflet-map-pane canvas { z-index: 1; }\n.leaflet-map-pane svg { z-index: 2; }\n\n.leaflet-control {\n\tz-index: 9;\n}\n.leaflet-top,\n.leaflet-bottom {\n\tz-index: 11;\n}\n\n.tb-marker-label {\n border: none;\n background: none;\n box-shadow: none;\n}\n\n.tb-marker-label:before {\n border: none;\n background: none;\n}\n", - "controllerScript": "self.onInit = function() {\n self.ctx.map = new TbMapWidgetV2('openstreet-map', true, self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.map.update();\n}\n\nself.onResize = function() {\n self.ctx.map.resize();\n}\n\nself.getSettingsSchema = function() {\n return TbMapWidgetV2.settingsSchema('openstreet-map', true);\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbMapWidgetV2.dataKeySettingsSchema('openstreet-map', true);\n}\n\nself.actionSources = function() {\n return TbMapWidgetV2.actionSources();\n}\n\nself.onDestroy = function() {\n self.ctx.map.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasDataPageLink: true\n };\n}", + "controllerScript": "self.onInit = function() {\n self.ctx.map = new TbMapWidgetV2('openstreet-map', true, self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.map.update();\n}\n\nself.onResize = function() {\n self.ctx.map.resize();\n}\n\nself.getSettingsSchema = function() {\n return TbMapWidgetV2.settingsSchema('openstreet-map', true);\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbMapWidgetV2.dataKeySettingsSchema('openstreet-map', true);\n}\n\nself.actionSources = function() {\n return TbMapWidgetV2.actionSources();\n}\n\nself.onDestroy = function() {\n self.ctx.map.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasDataPageLink: true,\n ignoreDataUpdateOnIntervalTick: true\n };\n}", "settingsSchema": "{}", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"First route\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.5851719234007373,\"funcBody\":\"var lats = [37.7696499,\\n37.7699074,\\n37.7699536,\\n37.7697242,\\n37.7695189,\\n37.7696889,\\n37.7697153,\\n37.7701244,\\n37.7700604,\\n37.7705491,\\n37.7715705,\\n37.771752,\\n37.7707533,\\n37.769866];\\n\\nvar i = Math.floor((time/3 % 14000) / 1000);\\n\\nreturn lats[i];\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.9015113051937396,\"funcBody\":\"var lons = [-122.4261215,\\n-122.4219157,\\n-122.4199623,\\n-122.4179074,\\n-122.4155876,\\n-122.4155521,\\n-122.4163203,\\n-122.4193876,\\n-122.4210496,\\n-122.422284,\\n-122.4232717,\\n-122.4235138,\\n-122.4247605,\\n-122.4258812];\\n\\nvar i = Math.floor((time/3 % 14000) / 1000);\\n\\nreturn lons[i];\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Speed\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.7253460349565717,\"funcBody\":\"var value = prevValue;\\nif (time % 500 < 100) {\\n value = value + Math.random() * 40 - 20;\\n if (value < 45) {\\n \\tvalue = 45;\\n } else if (value > 130) {\\n \\tvalue = 130;\\n }\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"fitMapBounds\":true,\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"tooltipPattern\":\"${entityName}

        Latitude: ${latitude:7}
        Longitude: ${longitude:7}
        Speed: ${Speed} MPH
        See advanced settings for details\",\"markerImageSize\":34,\"useColorFunction\":true,\"markerImages\":[\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7b13uB3VdTb+rrX3zJx6i7qQUAEJIQlRBAZc6BgLDDYmIIExLjgJcQk/YkKc4gIGHH+fDSHg2CGOHRuCQ4ltbBODJIroIIoQIJCQdNXLvVe3nT4ze6/1/XHOlYWQAJuWP37refYz58yd3d6zyt5rr1mX8B7S5Xo5/0nPYaNFM1PY0gGqOhfAgQCNBGlWFFUAYEIeihigbhFdZQwt85BV5Gj9r/718R2XX365vFdzoHe7w6d77xnPkn4YpAtU0YiizNJcmPNkMQFkDiSlowHt2HNtGlTSJ6B+pTpsKTfKgTj3Pi8SMtFtEZnFs8d8dPu7OZ93BcCHtt0+OiL+FJjOiqy5K5dtLwD4PBHGvy0dKLYo8B+1+lAldv50FfmFzWX+84i2M3a8Le2/Dr1jAKqCHtl2y1wC/pEMP9ZRLBaYzF8CCN+pPluUkOKfB6qlmk/dBwTyt8eOv2AZCPpOdPaOAPjA1h9/SJX+TyGXuz0TZi4EcPBeOk+U+RErZh2YyMAyQJEoZUjFgtkCAEScgDyx1hmInTglqDj2U1X0WILaPbWvwHO1WummeuLONhaXHTf2wsfe7rm+rQDe133j/i5xPyrmCr+OouhSKPbdQ5fLiezTIYUBQGMJBgYWxMYSISZhbxgQT8wGAgDiwWxUvCiBxKhSKOqdh4OyV5+6XiEfK/kjVOXQ13apG+I0+adKpXaG0/Si0yZdvPbtmvPbAuCNT98YTBhT/8fAmEpHoXgKgPe/6gFGP0nwG8s2YykcaRCAYYQ5tKTkDVuArDEwMRF5AICS4VZ1AQBSr6oEgL36CBAvlKqIsyLOKQl5TZH4uN+TawDuY6o64lWTJX20v1S633uJNvfmvnbRERelb3XubxnAX26+5gDy6Y9HtrU/wERff1XjSt0WwULDmZEMawPOgilgQ4FaGCEygaXQMQyRMaxiUijUkAEAImIGAFURAOrVA1AmI1ZExGuqoqkVFefhyGtKDql4X4eHc6LxJof0VIVM3nVc4uXaHUPlo0Tpc2fv/zer38r83xKAd6y74iImO31EMf9REA7cpdVBY8NbA5+dFNqsCTQipkitBjAUsLUZNd4qm8AyjDMmJAIRhDzDEBEbJkBVAyJWQJ14AEaciIeSGicOgBeBWNHEeXLkXIM8UvFI4bVBCVJNfdk7STd5xOcp0LZzjIqV/eXq/4i61edM/eaN7yqAqpfzf62Nf5LP5lbko/DbCuxU4saEN1mN2kKTzQbIkuEIEWfVagRDEVkOyXCkVq0aDg2p9YYNAySVerU0WN1R27Jjo6ulMQ1V+ggAOgsjNRNEus/IiUFnYUy2kM23AcrivXh2RiTxjhx5iSmVWEWdpmhQ4qvwSBBrXVPfqDmuVsT7C3aZvKslyZcr9dpxdr81F8ynO/w7DuD1q/8y6kDw2872ticN0deG7wvQHXHmdxGK+1ibQag5ikweliIElNUAEayNYBCSRQRiYzf2rNtx11O/rC5d9dj+1aQyM2Pyz3WGozaNisYNWY7SYtgWA0A5KUVO4qAn3t4+lOzYt+Grh+bDwstHzvjA2tPfd1Z+39FTRhGpi7VBKrE4nyBFDKcNJL5OCerqUEXdVeEQb0mk8lECjR0euxe9cqBUOnoQ6RkXT78hfscAvH71X0Z5kf8Z0dH2CgNf2NkI0d0ZbmtElMtFVEAQ5BFIlkKb00AzFJqCGooQcJjv7t868P3/ubayZvua48ZlJt57xLjjB/cpTssXokK7IQNrbeoZ3pIRJm1aYSUW9cwixglZ7xNU40ppY7mr+sy2ezt7G1s+vP+EGfd/+fS/Ko5pH9/pJK04X6MUDSRapcTXkXJN46QKp1UkqNVqvpxVyLzhOajihh1DpVkmrJ7+uak/bbztAF6/+i8j62p3j20vbgXR+cP3LYU/Djg/KcsdEnIWERcRIk+hzWtEOYSch2U76tk1T6+84Tf/NCdni2tOmbRgy6T26WOiKDBhGFEQhrBhiNAyjDGiQp4DFgI8AChg1BGBXOC9p8QJ0kas3jvEcUxxnLgNpTW9izfdOqGWlve7+OOXrThk6qEHKtKehq9xIlWkvoaYytrwFYqlglgrcZxW+oXSz+ycpOLmnsHypDTIfuTNcuKbAvD2288x22dn7hrVnt/ATBftBE/CH2aCtqkZU6CI2hHZomS4YCPK+5AKHFB2ZNe2Nev/739/e9qY3KRnPzHtQp/LtnfkMhnKZDMa2oDCTIjQhghDC2MCCQITAyYxpmkhAIAZDDA7l4bOSeR9YpLEwfkUjXqMOE0QN2LU4waq9aGBX6/+d7O9sXnu3579jbVTx02dlEilL0FDG1pJG64cJX5IGr6MupY5duU1npIv7sTQ4196ytUDx8+sf+TN6MQ3AyBd8+L8W0a15zYw0d8O3ww4vC7ijlkZU5QctVPE7QhNEVlTRNYUjHcy7tu3fuuVSqXBF8z66962fMeIfDaHfD4nmUyWsrk8BdaYIAh9EFoxzExEysYoAQ5A0ioAEIpIBGZmAM459iKaJo6cT209TnyjWkOSNLRWi1GtV9A3sGPg56uvG1vIZ9N/OO9rM8jS9oavSOwqaEhZYh3khq9K3fdpXWsbvdR3MoYCV/UOVadcOvv2C/AG9IYAfue5j1/U0R5mIhNctxM8yvxLyMVpOduJyLRRnto1MkXK23axlB27sXtT1z//8vqDTt3vk/fMGnX4xGyhiEI2Qi6X1Ww2S7lCIQ3DkCxzQEQKYADANgCbW6UHvwcRaO6fAwCjAewLYAKAcao6UkRIBEniEtRqNVOrVKjeSFCP61oaqurKvqe237P2lnkXn/X/PT9l3OT9Eql2V90QN1wZdRqSuhukhi9T3Q2s9ki+NDzHWppeUqnG/qsH/+b7fzSA33ruI7ODIDh/RCH6KkEZAEINfhia4n4ZO0KzphN5005Z06aRaeOAcjP++4Ff3P/86hWTLjr08i3FfEeurS3LUTanhVwe+XxOwjAw1loLoB/ASgBrAdSAV232Gc0NyJGt70+27mlrzNT6nAEwDcBMACO892kcx1KvN6hUqWu9Xka9XsfgUP/Qjcu+Nf3g6bO7zj7urBNT1F+quxLXfUkaMmDrviQ13+8THdqYqvuLZpfq+qrJNXFDbrp87t0v/cEAXr5iduiTMQvHd2QnKDC9+bC9NUfF9kwwgvNmBGW5Q3O2SFkzAkaCg/71Nz9+2MTZ6rlzLs4Vi0WbyWS5o63N5fM5G0VRaoxpA7ChBVw3ANMq1AKoHUAewCwARwHYvzWctQCeaNUrt4pvgeha17Gtevt47+M4jrVSqZlSqepqjQpVyyX/8xU3VBHF2T//+OeOFbgXaq5fa75ENR3SarzDxDToYz846FTORbPRV7oHG9sm+qEPX3TEM3vc9pm9AfiBP53+T6Pbwo0Cd4aog4p/yXK+lDX5IDIFZDinGS7CckEM+JB//u9/e3Z8NGPTgjl/Maq9s8N2FNtcPpc1bW1tFIZhaIxJATwFYA2AtAVWh4hERBQByIgIE1Gsql8gou8AeAjAfQAeVdUvEtE9reFFIpIloiyATgARgCqALQAGmHmUtTYTRWHDhhaGYE0YYmbHEXZj//rBRc/fXTly5qGHEus2FUceCbxP4DShRJ2mvuIFboyqG5kNcNuWVM965MbNd71pAC99+vADA+MnR6F+TeAg6h1TeE/I2bbAFjVLBbJcpIDzZNke8qNf//yxKblZWz42+9Pj2opFbutop7ZCQdva2hAEQZGZXwGwDEBDRCJV7VTVfVV1BDNPUtXZqnomER2tqi8S0REAzgJwUqvMI6JBAM+p6pdU9f1ElGu1E6lqUVVZVYWI6gA2EFFijJmSiUIPsDbXmGT3b59V6Kv0dd334uLGYTPmHK7Q7lRi65DCawqviXWSrEm1PlvgWMh9KPbut+/77Ohtj/97d98bA6igo7aM+O/Ogp0l8BNFPQhyY2RyE0MqcC7Ia2jyGpksBYj2//WDCx9uk/EDZ8783JhiW5HbigXpaG9HNpvNMXMGwAoR6SWiUKS5KhERS0QqIgmAHcz8sqrOA7AdwCcB9AK4CcBvAdwP4EVV3V9VPwGgC8B4Zv4PIqqoqgPQYObEOadExC1A60RUJaLxURQaZqoRW0NEsm/xgI6u7rV9L295vmvGlKmHQ32vk0QdxfA+oYTq+Vgbi70mR4p6BEaKlTid98S/9f4MV7wBgF/66AEnFbPUz+z/VNTBiywLgxxCFDgwGQqR5wznOeR8+6p1657r6uopfu7wv4mKbW0oFvIoFovIZDIBEXkReUlVG6o6Fs2N/EjvfSczj2Hm/YnoY6r6Ae/9w0T0cVXdSkTfE5FsC8iTAZwI4DAAjxDRj0TkUABTACxS1csAzG39MHlmzqvqGCLKt1xZA0Q0QERtQRBkDZMngrcmNAeMmB08uHpxNsrz2pFtbft4TWInDZtSLE5T8i7uSKRS8XDjBX4fYbnusI2jMkt/tGP9rnjxrl+gICP4Riagrzb1ssKa4CkrYRhwwBFHYGSUOZJKo8oPP/vCoV846opSoZCnQj7HxUJRMplMgGblR5h5wHtfbE1oZAvIHBFtVtX7RKTQ4pSrnHOXAThQRK4BcIaqNkTkRRF5UVUTVf1462/TVPVSEfm2974qIm3MvBhAl6pGAEYAaBcR45zLiUiPiDxKRC6bzZpsNhtGUaj5fIG/dNTltYeeWja3ltbVcGgMZX1IWbUUqDUBbBA+OYxDPuDLSORq6KsN76s48MvzZnwwlzNDgaFzAIBAi0LKtGVtEQHlOaQCQpOHoWDWL+9+ZODCuV99cnTbmM5cIY+2JudZIpronHukxUWemavOuZIxpuG9H8fM8wDMJaJHVfV0ANcDOIyIPg5ghTHm+0S0UETWq2oCoA/AI6r6C2PMgyKyD4BPM/MggJ8COIGIFqnqV1T1YADbVXUjEfUaYxrOOcPMBVXdCmCutbZirQGIlIBwavucl2577NaJM6ftO1nJ9aY+YfEpvDryknamSNdAMQ1AGwxdc/DqDjz9k/7Nw5i96ixBSK/MhTRxJ7oUbracmWAoVGNCtRSCYOxLazfcN7VjdjK+beK4KAqpkMtpJpNRABNVdT2AowHUvffjAYgxZpNz7hUiuk9VT1LVWFX/iojuBfA1IrpfVRcS0Xne+6tUX33+M/zdew8AzxljLvPefxTA3xPRIufcpQA8EYUAFhPRSCKaKSL7EFGgqjtU1RDRZmaeGIbh1sh78s7LxM59R09um7585fqNdtqUMZOMMc4igE0DthSppcYWL80VTNbyX1QCPgNN1fJqDvzi0tnjQviObGia3Ee0JEAml+E8DOUo4pxaE4GUJz3yxJr9/vSIv+8uFAu2kM8jl8vBGNNJRE+q6grn3AZV3QRgi6q2AZjHzHNE5FEAp3vvv8HM8wFQSywvADAPwDgAi0TkPwDcBWDhcFHVh9FcXH9ARE4BMI6ZvyEiHwYwSVW/CeB0IlpERJeo6hwiepmIlnrvVzLzemZex8yDzDwZqlUikGGm6R0H66+evuPYafuNynvFkCCF4xjiBd67otN4C4GmEDAqTuVnR3++beWT/z5YfRUHio8/0dEe7DynJTUvswmmEiwxWcCDwGyee37j4ydNO6ucy+YmZMJQM5kMWWvHqmqPc24eADCzENEGAMvTNH2AiM5Q1W1E9GkR2cLM3yOiS0TkO0R0lao+zMy/8N7PBHAmEZ2C3YiIoKrdqnqjqq5i5j/x3n8bTQt8iapeKyKbjDGfFpEhAGOccw8EQdBhjPmQqk723rP3PrTWvhxF0Xgi6vHeayaTyx075fS7nlvxcPGgg8ZNIjHeSKRMdbEUIEHwEuCOA4DOvB25vSRnAfghMGxEFNRb7ZoM0HFNadFeIjvRgMFkhEDKbEl8Oqq7u3bs+/c9cXQUWo2iCGEYsqrG3vvHAPwEwL2qulZETnXO/Zm1FqoKVf2Bqh6qqr8SkW3e++tU9T4i+ntVnem9vw7ARQA6ReQ5AL9yzl3vnLsewK8APIfmovkiIrpWVWeo6t977x/w3l8nIluI6Dcicqiq/quqgpnJOfdnIvJR59wmEVlCRD9S1QeJKLHWmmw2hyAM9bhpp47q7q4d733aSVBlkBoNQGxgYPdVRZ82N5In9lS7dp42GgA483hMyUY0RXgwXzAjQgUtshp1WhOR5YgDzoiB0U2baqsPLB7z0oxxBxWz2Rxls1lh5gNVdbn3/rwWR68moi5VPZWZt4nIvgBGquoRAH5BRH+OprH4oYh8XlVPQXMvfIOI/BJAFxF1qupxRPRBIjpKVSe3dOtdInKbqj5PRIe3RHayiHydiMYDOIuZfyIin0HTfI4kIgAYa4y5UUQaAI4QkY8ZY5YR0aGq0kcE8k5NNS4t665u6G9r47xDCi8pqabsNbFe9WkoRvU0upYl8GunnqebX7kZQ00O9DipLbKjRfQTPWnXYyBTBxMBBiIML2IVkt20sf6B46d9rJjJ5chaQ0EQRAC2pWm6VlVXq+rZIvIXSZKELcX/Y1U9RlW/AWC8iJyqql9V1aOcc99W1SXMfAmAh1X1qy3O+rKIHCMiGRGptUqude9iIrqWiC4brisiDxHRt1X1KFX9qnPuowDGe++vUNUPishNLQkIiOjPVPVs7/02EVkLYHsYhtYYg0wm1FNmnZPftKF2lFPJisCIkhE1DFiFaNLr1i5R+PntGR5lFMcBLWfCxxbhrgkjgqMAjCKgkrWFX48KZ7RHJm8CziJLOXJpUNu4omAuOfbKOMxkKBOGHIbhHBG576qrrtLHH3/8QmaOdtdd/5tIROLTTjvtyc9//vN3BUGQs9aOA3CyiDxXr9dRrzfo2gf/Ljt1TpyYIMnWtQ4nVW2kNd+bri41fOlMADkQerb1p4/f+WGcaS9X8HOLUQIwCgCUdFGi6ehBt7k+3k4DqQ8cOd2+mQdPnP6xijHB+MAYhGEoqppL03T/J5544iRmpvnz5z+4Zs2a1dOnT5/+8ssvr5o5c+aMWq1WSdM0VdXORYsWHW+tXXbmmWcONV2jQG9v744dO3b0jR07dvSIESNG3HbbbbNFpHPBggWPtMTvVUREWL58ee2VV145bcSIEU+ddNJJ1RY4unLlytXTpk2bEoZh2N/f37dw4cKTrLUdxWLxvnnz5pnf/e53unDhwhPa2tpWnnfeecekabopCIIMEYGIyBjGCfufvmbpltuKY6a4LKkzCh8PpZu913g0oIsAOhOKMQTElyvYPrsY43IRP6uK8wCAYHrUo+gpiXoaG+LR0X5VaNgxNEAHz5pz6PIgMGBmBTCKiJZVKpUjjDEmTdPG/PnzPwSgLCJHoLlY/omqXgLgWSJauHjx4uNPP/30obPPPnsAwGNoLl+O32Xdt/a3v/3txnK5HM6fP/+3aJ2JAAi89zkAUwGcdOqpp+YvvPBCnH322fEJJ5yQA3CH9/5YY8yft0C+SkTmP/roo72NRqPjhhtuODCTyRTPOuusRy+88MJVd9xxx8cWLFiwiog+oqp3ARgVBMEO7xVzJ70/v2jdHbNGqu/16uq98WakmuQgANhsU98MRQwMP7N0iYxhUuybD/n3WzqlAMROROElzfY3NrXHrtTNFHTkMvkiGQNiZhGZ7ZzbPDx5IoKIXK2qZzDzd9F0T/0pEV2qqoeKyN8BwLZt27ap6hmq+l0RmQXgZhH5iohcpaqrwzA0RATn3DXOueta5buqeoWqnqWqT9dqte8DwPbt2zeKyBGq+l1m/giA7wL4map+jYj2S5LEA0AYhp0AvsvMp5577rn3Axi/YcOGxaoKEdkCYBYzqzGEMMgUWILRjXSopzfekFUf5wUKYXYQCoZhykcM08C+DMUMw7Rva8sHqHZCJFD1VtTDaYLuoe3xrLGH/Yu1NiZVtcYAQEVVy7vpmPNU9VHv/RUArgZQ9d5f473/qYj8OwBMmDBhPIBnnXNfAfAj59w5AK4F8DURmcfM1JrY/4jIrSJyq/f+XlV9vmVMPlEoFC4GgM7OznEicmPrB3hJRC4Tkc+IyI+897cFQWBay5lrVfVKVX30lFNOOUZV/aJFiz7YMi79RFQiIgbg2NrazHEHf7+70q1eGiwkROoteQkhOmIYp8DQBGUcYIVwOJMepCCAkBCooCAnUPVwXoU1rrXVoyi7nwgoDO1QyymwzTn34d7e3p8B+NsWFx4AYLP3/l4iuoKIHhaR/yaiLw1z6rp169Z57+cR0bUiAiIaVNU7ReR5Y0xcrVbPbf0ek1U1DwCq2qOqG4jofhHZUi6XAeC7IkIAvqCqIKItaG4LZ4jInxERvPevtK5fY+b7W+0eBGD78uXLx6nqd51z85i5G0Bore1rNJJsxuan1EumFo3w3mtKSupAMASNRJEACBk6ixWphWCaKs1tqegVUIWyiBcPIYhRQlLKhQccNDtW9YEIh0TkiciJyGFtbW29LfCCxx577PtHHHHEhdbabd77bzLzFap6jPf+X5o46Jf333//qWh6kP+P934HMx8F4HQA53rvkc/nl9frdYjIQbsw99SWy6opPvl8BQC6u7u3ENFfq+poVb1IRK4iIvHeX7dy5UpKkuR8Zka9Xv9WNps9n4j2B/DNkSNHnrV9+/ZRIvIhIjpMVZeoqlfVEcyQ6WNmpQ8+nyva9m4IO/XeQ1XFE6UKfYkUhyrTEVDEFkAWO4NuZAuAsPnDKlgFzih8ku0cU5y4NQiCxFrLAPYDUCOizxpjrgAAY4y54YYbvtwS5f1E5B9UdSgIgloURR8BIESEO++8c8qmTZtetNYeHYahdnR0wHv/pIhsrVarvX19fQsA5H71q1/dYq01pVKpkCRJXCqVaGBgwDcaDdfX1zcRwDELFy788JIlS96XJEnBOQcADSIKmfkSIsKwpXfO/bmItBljLlHVa6dNm/bIE088sR+AMUT0WRG5kIgmWWtfIWPcuPZJDJ9r90hIRVTEq5KAlBIIdYH0UCg6FMhZUvDvjSDVnZBhUhUSUijICxHCbDFXZGOMqKoH0KmqQ/l8/ptdXV0/rlar38rn8zs5hJmJmUM0jyPb4/j3h/ze+ylLly6dgr2QaepX3Hnnnefv7ZmdoyUamyTJWABoHvTtmbq6un4xa9asSQCuA7DSWvtSo9E4zHt/dbFYvKLRaKwF0E5EwoBENlKVMOPFkcJDCRBVUlEloLQTLgWz1987FAhImCECJVEh8Z6cdzBk20ITkIg4Y4xX1ZFoHuJM3XfffT/S29uLLVu2oFKp7HQ9/W8ia+2RzHyGqv6TiPzjsccei97e3kxbW9uZACYTURVNb7mIiIYmJIOwLUWqTqQVIqFEDFHV6nC7orDMBB22LOzhWbRC0LJRLalqGYqyQWAJVDPGVJIkqQPYrKq9AGCMmQoAaZpix44d2Lx5M/r7+5Gmbzn4822jVatWvei9/9M0Ted77/9j5syZawAk27ZtswCgqt0AtohIzRhTssZWDdvQkA4RtETaxAOqZSWWnXgR1Kr8/kTbG2ThtaAE9QQSZWIQ2EilFteyhoJCa4lxYMvf9xry3qNUKqFUKiEMQxQKBeRyudcVsXeC0jRFrVZDtVrFzTffnOnp6Tl2/Pjx944ePXrt9OnTzyGirY888sjLCxYsOERExhPRDGvtswACrz4m60pOqIMIBIX4ZqCYAWsZLXumAtid6z8A5DSvlgkKFkcMiBERqHUDiUu8994SkQCoEFF+jyPfhZIkQX9/P/r7+xEEAbLZLKIoQhRFbzugzjnEcYxGo4FGo/EqCejp6Tnv5ptvfk2dH/zgB8sWLFgAVS0CqHjvyTlnq2mFYF3VORnJICKwI2IFI0Qi7TCtLaYCVgnbAdoA6GRhaoPXhipIVJkEUCXP7CrleBAd2RHsvYcxpopmfMreaICZN6LpQWYRmZSmaeeuk7LWIggCWGsRhiGstWBmWGuxqwUFABEZ9ilCROCcQ5qmcM7BOYckSYbd/XuiTczcT80YHHjvZ6MZZ4O+vr5hx+14Va1Qa/M9WB0Asa+SUCcIRuAtg5QEBKDYrEJrwdhiIXhBRQyIJkMxQxQvkELh4RUq4kCJ2VHdOLiOx+YmmTC0trWwnQOgsvtoiegFInKdnZ3rRo0aJT09PTw0NAQAm0VkzvBzw5N/B0mMMU+pqhk7dmxXsVjkzZs35xuNhojICDSPRpPt27c/WSgU5hLRC95722g0aOPgWnbcW5VUBYCSJYBBChgQzWnt2J4BsJyheFkVr7Q6Hc2kZYU6ARSejCjZFN259UOrc6reOucMEfWpqnXOPQIAhULhN8PgMXNl3rx5Y4IgOIuZz46i6KyTTz55JBFVmXnFO4nYrmSMeTKKooEPfvCDs40x8621Z3d2dp566qmnxsxcArC1s7PzkVWrVi1X1QBAv/eeiYg2DK0upOgpiCBQIlIBBOrBOgTCCAAQ0jUQrGS1WF1vUPewLlTlKoQCOARewOqVUgzmtlXWTWuKiqiIVAAgjuOtuy1bgtNOO21ET0/PhO9973sQEXznO99BT0/PxJNPPrkDQAO/97C8k7RBVaO5c+ce19nZmb3yyisxZcoU/NVf/RVWrFjx/kMOOWQ9M3dXKpVRjUYjbKmGinOOnPPYWt04PZGhjHoQCZigAQsFpFwbxqlRpx6k6LI6gK5Kpz8zm20d0JHWQFAYTSUlALDexSNdEB+Y+nQxpZRlppSZ4ZybdPvttz9QqVSOt9Y+SkR+xYoVxx522GF4/PHHceCBB2LZsmWYPn06nnrqqQOZ+REiekZERr+T6BFR37hx47rWr18/NwxDvPLKKygWi3jhhRdw5JFHolarzXvuuee60jSdYFordxFJnHNI0rghiGc4jb3xUDEQEngyYEBrwx7KcuJHZzux1t79KZQ++iv5AHTnCadVBZGQhULh1SsIMfoe7KlsGRqTm5Q1xmkQBJtV9dijjz766f06bwAAEgVJREFUnpUrVy4EgIMPPjh300034bjjjsOaNWtQqVQgIjjqqKOwZMkSzJs3b/Xy5cstgFUA3rZF954cr6eccsrYxx57DJ/85CexcOFCDA0N4cQTT0S1WsWjjz4azp49+4l6vc5Tp049TVU3eu/hVXVbZUN/TH33k8c4DVRIiMFEohCjCIdXLC6VY+44DV+zACCEXiiWgnCkEp1EpKsEqqTEIsTq1Axg+eCy/kczp+QmqDZfuXpRVedNmjRpx9VXX32hiEBEsHTpUtx5551YsGABnHM47LDDcNNNN+GAAw7Al770pc8NPzdsUXe1rsOA7n4dBmjXK3NzgbHrZ2beWQDg7rvvxq233oqLL74YS5YswY4dO/Dkk09i7ty5uOCCCz4bx/FPRGSUiNydph71ap2W9T9eGGgsr4iqZSVVsLJ6Z5lIlU5srfmWAlgHtE7lDjgP5SjgAWb6MBTtoroMgpwoERTwniiJhwq5aPrxB+YOWwuQIaKEmWd573NBEHSoKosIpk+fjltvvRWqitWrV6O7uxvLli3DV77yFRQKhVeBtzcgd/2+exmm3bl3dy4kIowfPx4LFy5EpVLBpk2b0Nvbi+7ublx22WWw1ro4jgsARgJYVq/XUG/Uk2fK95+ypXxfrESGGUIEMhYGTP1ovQOYOr2+kcjvVt+K9c130cp4slyX4nDnBqYbRCAGkTZXUELIVtPeezeUu3rjOEaSJFDVpwEcmKbpLcMTnDhxIm644QYEQQDTPDvBNddcg3322ec1IL1e8d6/qryZOruDffTRR+PrX/866vU6kiTBAQccgOuvvx5hGKI15hki8lTz76lura/fUUt6F4siJIKCiREAakhB6BnGp1ST9lwbngJ2CfE99Zd4cPzIcDqg4xl4wQl64EE+BlyicCnYanHz4RMumviR9vO7C4UC5fN5JqKzVfXlKIomtzzGr5nwGwGwOxe+ngi/ntjuXowxe/s+0Gg0+ohofxG5o1KpoFqv6+LBn496dssPt6dcmWAtlCOCNRDKgJgxEopDoLRl60Cy5p5P4Hhgl/A2NbgmTuUGBeCBOUTokVZAtyiIFJSk5QmJlJKeyvaeer2u9XpdVPVxVZ1Zr9dv25PI7Q7M3sDbEwe+0Q+wt/b21vdwqdVqv1XVaar6eJwkqNdj9JY3bW9IKU5cZRwUDNPcuagBE2G7Kg5RAKnI9SD832HcdgJIARYOVdyknXtjoTpBoaRsTPOMHQy7fMutQy/qQzOr1arW63VNvd+kTc/NfO/9I3vTXXub0N5E9/U+v57Yvp7+VFWkabpYVc8DMJSm6aZyqcSNRk1fxOMHPb/5v+pQtWwgUBCxErGCiOJhXHYMuRkU4r7XAHj3aYhTAaC4rakI9dNkMMSWPBhMSsRKmjRKIyuuZ3Bzfe32crnGlVJJReQ+Vc3HcdyuqgPD4re3ib1ZHfhmVcDuYO4JxNaYetI0HYvmMen91WqVqo1YNqVdW2uutz9NSp3KTNpcxMEYgjEYVNULmvVxiwLVu09D/BoAAcAZXL6j7F9SBVRgiUwPkRJYCQaqrEoMWrrqp4WN2ZfmxXGtWq7UqFwuJyJyP4A5cRw/qKryelywNw7ck+58I336ZvtR1Uaj0XgewMEicl+5XPblcpXqtXJtk33x1KUr/6MAbnKdgQKsDFUVMTtUYFWBvpLvohRX7orZqyJU192K6tSz9Qv5HPcQaCpBZyvjRSiyEFIVkDioiBbL1W3LglGduWJ9LKDExnAtCIJEVU/w3t/MzIfsbiD2dn0jHbkrF+1qSPZkXHY3MMNX59ydaB5ePdNoNLZUqlVfrpSxOvO4earr5xvqvm8iGfggBFNIyiGYQwwQ4xwABqqLhmo+c885eJVf7NUx0gDE4iv9Q/JYc1+MDABvDJQs2DDYhlBmxD2Da6YNxOulW9dsr1TLWiqVtF6vrwawXFU/7Zz7TwB/FCf+MUuW1ylJmqY/F5GzVXVZvV5fWy6XaahU5q26asuA22L7hlbvR4a8NVAYKFsgMBACJZDm7mNHSZ41HpfujtdrovS7bkV58p/oRwpZ8zIIhwM0C0SLoBipCmqNnaHAhq3L7MT9D9mfhjIrrYRt3nu0fG9VAKd673+Npq8t82a5cW9ADdOb4bZdljfbRWSpNt9BeSJJknVDQ0MYHBqiwXRHd9+IriPvffpa4YBCE0I5grCFMRlSGFoF4DMt3ffDUtXLPfPxyzcEEADGnoNH01gWFLNmChQhgTJEOqiKQIQEAiPNU09+Zf3jfZNnH3yY9mVWasoFL16sMWVm3gzgNO/9KiJaq6qTdlfyewNv9+f+QNCGPz8qIgLgaFVdVK83egcGBk25UtWBel9f/4Q1x931yFUbYLWNIxgOoDYgDSJYE6IB8CEEjFKg1D2QdscVfHn9r/EaB+YeAdx8B9z0+Sgz8HxgeR6AMVB6hgzaVMk3Q/2JSQHvJOra+GTXlMPmfEi6o+d87NpTLyTeN5j5ZWae6b3fV0RuIaKZqmr3ZJ33BNzuAO4G0B7vMfOQiNyqzcBN8t7fN1QuN0pDJVQqJe2v9u2oTt9w0l0P/uNz3iQjghA2CMmEGXgOCSYDIqJuAk4AgHrDf7We6u/uPx97zO6x13fl1tyOtfucqRcXM+ZFAHNAmA2iu4gwRkBKos0jAVXy4vKvrHvslWlHHHZk2m1eQKJ5VfXOOauqG4Mg6FXVj4nIalVdpKoHqSrtsrzYed1VXAHsDaQ9caAQ0S0iMoqIPkBEDzWSZHWlXI6HBkvBUKWsQ2nf5uSA7SfeueTqFxPUxtpQAxMSmxBqAhKTBZhoBYALAUCBW3ZU/D6Lz8E1e8NprwACwKQv4nf1fvlUMWsJwEgC5oDpIVJ0EhGrJ6sAICCXuvYVqx8uzXj/YZPSWFbWelyHeA/nPRLvqwxa3XRN4COqugrNKPwx2ozifxVww1y3K4CvA95WAHdQ8xWHDwJY4b1/tlwupwNDVVTKQ9rfP6j19h3dsv+Ow29bdEWvUmO0CWBshowJCTZL3kQAW1pPTb1noPTK9oG0no7Cp9b/7LWi+6YAXP8zuMnn4rFG4kfnQ3MYgIgIU5jxDCmKCigBpE1xZlEfvPDSErffrFkU7BNQpSutxQ1PLo6zSerFi9RV/CvMXFXVQ1R1H1VdhGaIbxnAzgQ5u4vtLsUx8yMA7mPmbQAOJKI2VV2XJMlLtVqtViqVaLBUlUqpn0vloTofOhBVMptzv1h4dd4Yn7cR1GSJwwhiQhIbIjUBthBwJoC8ElzvUHqzKL5+/+l4zQuGu9Kbyplw4m04Ix/xjI68+W6r2gZifdI1dFSaEEtdOW2AJYG6hnqXEMaOnL7ptGO/+L5kjVks2/JjM5nIZKJAoihLmUyIIAjIGANjTEBEHSIyWUQ6RWSdqm5V1YqIpC3RDImoQETjiGgKM5eIaKOIDKpq4r2Hcw6NRgO1egzvUq3V6l5Hxhuys9OPP7T0lke7tj41nQNiG0FtBmojeBMR2yzIRNhKQh9U6L6kkMGq/7t6Ii8uXoDfvRE2bzprx0n/hc93FLiQi8x1zYq0CdAHvcdkV4V3Dupi9b6OgosR+wRGvU3PPuXSHcXcPiMGnvAvcJIZlwsjG2UzMESUzWa16SExZGxLGFS9sVbFK5SUAGBYWYoIMzN5BbnUgSCaph5xXCfvvSZJouVaw1NWejrfL3NK1a07frHwmpFsXcgRvA3hTRahNeRsHmKaXpZtIDoa0P0AoBb7SwZqEt+/AP/6ZnD5g/LGnHwbvtlZCAYzAYbzJwwo4U5xOl0aUB8jcDHUxUSuoQ4pJE0gmbCt9vFTLm4UM2NHDCxNlidDweiQOAyCUDkwFLBBEFhSZrVEqkDzHLEVAiA6PFBFE0pFkjhS9YjjVJ1Lkfg0sZ3SO+rI8NBSo7vvznuuz8S+lDMhwBbWhmRtVr3JgmwAmAhqAlolij+h5svfqMW4ZKiaFu49F1e/WUz+4MxFJ92GS3MR246M+bYSGEAizD8mJ4d6p+oa8L4OcQnUJzA+hhWnqU+gUdA2cPKxnylNHj/rmOrW9N7+F5JGOiQjyXIYcgC2zRejiVXFw5Np5Y3xMGxgxBMJPMSlFHtPUI1NG/eNmhNm8uODUzZse+nB+x78WVs9KXXaDMgYspyBNyG8iQATwIRZwIawYPOCQj4LICSFDNX9V6qJ5O5bgH/8Q/D4o3JnnfhzfC6yvM/IdvPXADpaLd0KoaJPNS+xmjSF1QYkTeEkVfYpGR8j9Q5WRKvjRkztPf5DC3j0iCkn+AQvlDdUu6rbXaPWn5KrCEEErTwXTTKALbDmRgSaGxNk26bmppoQc7p7ux546PE7ZHvfutHGUJ4DOGMRmEi9sSQcwgYR2GTgOCRvDFXVaJUU81sA9PcM+X92Trru+yT+8w/F4o/O3nbyrTiaGF8cUwgOIMZRreZegerDgB6YJiQSw0uqgYsh3sFrjMB5eE1gfAovHka9pjaM+ke2TxiaNnWujBkzOcxnO/KFXKHNBpnRAODSRm+lVh6q1odqPT0bkjXrnuW+oS3tLo1HsKGADIQDsAnhjEFAFgmHsDYCmYBSG4BMRgMQvQTQcYBOBwBVPN5TStd6hxvuPx9L/xgc3lL6u5N+hpGwuHl0u33a2N/nDiTSXxBIRHWCNMilMdQ7DSVF6h1YUxXvyKhD6h0CCKCCVLxa9YASKYlyK/AOIJAyCUFBDGImB4KlEEoMbywCCtQbQ8QhxFiEJqDYWLDJakBEm4g1UKFPDI/Rq16xY9AdZQzOXzgf/X8sBm85AeM5t8P0eXwtItYRbfZToOavCyDxKj81RCPgaKJ3iL1TAw9xCVgdvHcw6uBVm/pNvQIKpwJV2pkKBQCEFKoMYoKFITVGQQxPBsZYeLIwNoQQw3BAjiNEzNioQKzAebQzkJRW9lXcbXEqctx5uOryYUv1R9LblkP1+JsxjS1+MDJn7wkDuhKEHACQQqD4OUgExJPFq/EpqTglcXDqEXoPJYETDwbgROBVAQY7ABCIJQKYYQBYZogaWGMAMkhhEJiQPLMaG5BTlvWUsgXjvJahAxS1RqpfH6i5eYjxhfs/i7clj+rbm8VXQSf/HB8T4LOj2uwzgaF/0GZ2oeHuVqjq48zIQzHee4QiSLUZgwN4kDYdt0Kkqq38BM1XhYnAMMwKGDQ979y0rERIRbENQJWIPgDorF0m2Ei9Xt0/5N4njH+//zzc9XamRH5H0iAffiOC9gLOVeD8kXl7bxjyxYC+OqMv0VaoPsCEukAigNqg1EEEFlWBQKHUFC9SBoOYiEUhRDoIaInBiSgyBDpJoeN2m9qG2Mv1/SV3iir+s1zFbc9chLc97vgdzWR+uYIfugUnC/C3keUlHQXTaQiX7LUCox9en1XwIBENCqTcvM1FVe0gSAcMzYVgxN6a8IrrBit+IHFyrCF850Orcf/ll781Pfd69K7l0j/mJxhtLb4+ot2uDy3t1T30Vihxeml/2U1WxpVLPol3PA088O7/MwI6/ib819j2YDOb154vvBVSxfXdA+nEBz6Ns4G3T8e9Eb3mUOkdJsW++NT2UjpHVO/V5vrvrRfVh7f3pTNLdZyLdxE84N0HEEtOgMsRzukdcBUV2vRWwYOnbTuG3HZXw4J3wki8Eb2uQ/WdojW/RLz/n+CluKaZTMhzm4eJwB9aFHADFf1X7+X6h/4MG9+LubzrHDhM934KLyhoaSPB3/yx3Nco42+811UPfBbvWvD67vSu/0eb3enEn/K17RkeNExXvPHTvyfxeuVQQ0be9zn50hs//c7Re8aBw3T/Z+TScl3niuBm9cCbLLeXGjr3mA3yl+/1+N9zAEHQ6oA/rxLLBPF49o1Fl54vxVJ08Ge/kwvkN0vvPYAAHv8K6ur8BbVEnlNF6XUArNQS/ziJv2jJ5/Cm07W/k/SeWOE9UddvUJ5+pimpYhODTtyT1Y29fsOrv2fxhXj+vR3t7+l/BQcO0z2fc0ucEyeil+7OfV7xFYXI4gvx4Hs9zl3pPbfCeyA67cfmFiaziVX/BgCUcL1XGf27z/vz8S7vNN6I3t23oN8caW0//+lcF/0PC+4VIBJgZm2aPw3/y8AD/peJ8DAtOQEuZLfAQ0sK7Q0rbv6SE/Yen/L/017ojH8LZ5/xb+Hs93ocr0f/D6s769KBP+5xAAAAAElFTkSuQmCC\",\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic3bx5uF1Flff/WVV77zPeIQMJIYQxYRRBpBGcQFEEbVQQUXB6xW5tWx9+Cm07IYIitiJog2P7qu3UCN22aDs0KIIyg0CYyUhCyHiTmzucce+qtd4/zrkhQIIogz6/9Tz1nHP22buG715D1VpVS/gLktnZjg3P2wGz3RC/N9hBCHtjMgOxGjDZv3UAkyZim4EHQO4i2j3UkxXUb9kkcrb+pcYgz3aDNvLjOah7BSZvRnwLX/8D2axILM0Dtx9ODgGGt/P4GNgtqD6A764i3+iJ44dC9CD/jaRXyqzXrHs2x/OsAGhrL9sB8W/B7ARKwz/H7TAE2btAZj89DbAW6X4HHRknnzgW7KdU5fsyeMKmp6X+J6BnDEAzhLWXHYz4c3GlG8l2HgL3frDsmWqzR5KDfpnOykkIL8D4OHPecIcI9oy09kxUaut//CKCfp7qtMuwwb8DnrOd5nOcXIfJCryAOgEpASUwh5HiBMwKEAW6YF1chIghthtqL97uSxG5C8a/TXvsBLx9VGa/8Yane6xPK4C2/kd7EuWblIZ+itU+BMx93E1OFmLchqQpTmaDA0kAlyDSwSwizkAFfN84RAfOQASLCVACDVgAESOGDZjmSDwEtYO20bVVaPMCionjiPoe2eXNy56uMT8tAJp9I2X10GfxyQTJ4GtADn3UDd6NYv5niKtgyQxcYjinkCSYi3gHikeSLhDwXjHzTNlWB4hEYnRAgoUSmIIqxAQsYEFQA/JRNHZw+lqiTn90R/VGYuNKQl5j/cTH5JD3FE917E8ZQFv23b0oJf9GNnQd8PFH1y7rkORKLJ2BTxJcAqQOSQyXGEiC+IB4wZxHXMABeIeZQ3q/MBQRhdiDNGqCaMSiYTFBKIiF64FYKBbAigKLD6PFsYjt+uhOcwHdiUMRe5fMe8uSpzL+pwSgrfje+/CyK1n1dcBeW/7wMoZll4Kfhy95SARXMsSDSxxkIInifIK4gHpH6kAlggjOOwTBJEFV8FIQDcQCGIh6ighOFdMELQKYYF1Bg0KgB2ZuxG4kFqvw+cmoDG7V/cXk7Z9iulx2efvX/1wM/iwA7bLLPIe1v4m4RSTJuWDJI/+675OUB3ClCmSC9yA1cKn1dF3mSFLDRJEsAYk9wJxSTEzQGW3TXlEQC6G7sde/0gzDZ0Zlt5Ty9Arp4GBfnBWCgxghOkIhkBsxGK4QYgs0gHZAQxPtNLH41q2GH4jhNFRfwrzK20ROis84gLbkohLp4C/IuAXso1v+UFmLlK4gLc/Bl4AMfEWQDHzZIAFJhKQMLgWzhMayjTz0kyYbrt2T2Nq3a5WFE3HWqgYzNxeU81ao5ADVpJ2ldLI6G6YN+o3zStI+CF+9n1kvWcYub6hR330mIgEtIHSAYFgOVkDREegYmoO2QfOHCJ3X4thqDirn0rUX0Kr9rex/Uv6MAWhLLiqRDPwPafdBxN79SC3yS1y9S5JVoQpSEnylB5wrgSvTAzCt0Vqzmfs/32By8cs2xZ2vXGJHjo/KnlVz1aEsLZsXKVQkpIlXTHo6T8wFjU5iTELULFpEQmN8Gsub87lq2gy/5pUM7ftb9jtjgNJO07DQQHPBerMeYqsnztaGmBvabhNbVYivemRwfJWitADktbL7OztPO4C25KISvnolWWMN8OZHasj+L5Luih9QfAWSmvVEtwquAi4DyWay6aYHuO/8A1phYOkd9sbVTbdgVlYqJVk5wycpWZaRJY7E+2i44L2Y0Zv8CkgMCMQ0xOCKGAndnCJG8m5ueacba7pkw/Pksp2rvrkH+3/kXqY9fx+cbiA0HbEDdIzYBmvRE+12l7y1GRffsRUj/JBubR6xdbQsOK37tAFol13mOXjzzymNrQL+/pGnS1/FZXvg64IfAKkqSTnBVRRXEaQ8g7HFK7jnU/NHde7tC5N3RpKB4WqpKuVq2cpZSpJlkvrMSqVEvE8ty9JClSJJJIr44BwWY0xjNC9iWZ4HH2OUdrsjzpm1Wi3X6RTW7XZpdNviwsToQfodP92tPpj9z1nG8Pxd0M4mYtugEygaGdpWQgO05aCxFI3/+Mhg5WsUQ3vx0Npj5GVnh6cHwCVfv4x0ZAViH9py0WcXIpUDcPVIOiBIFZIauKrgKg6z2Sw8c0m72XK3uA+MuMq06dVqzSqlTGq1uqVp6iuVsqRpGtIsM++ceO8NEQQi0AGmuKAElAEfYxTAQowUeZBu0U3zTkc7nVzzvGOtVpdGqyHa3rTpUPvSjpVyreDgc/dGZB3aVrRlFE3QlmBtoxhXtPUQlr/nEVTceRQzd5c9/+GUpwygLf7Ke0jHykjrS1suavpV0vqeuDqkdUEGlKTsSQYUqcxmcvky7v38c+6yt/xqvHTwvEp90OqVTKrVitVqNcrVasiyTBLnUhEBGAXW9ssqYD2QA1MT3bQP4g7APGBOv0w3M4kxxm5RxG67nUxOTkq7ndPO29YYb9pQ55a1z3U/Opb9P3wXA7vtgbbXow1HbBk6aYSGoA2hmFgK+ggnxoEPYENR5r/3y382gHb/xQeQFm/Gr/0ImOuD9zXS6p4kg4ofBKkJyYD1gCzty9IfXlVsumuXm7NPrC6Xh6sDA1XJyhWmDQ1ampa0XM689z4FNgP3A0uBdr8vSk/veXpceFj/9y39/6ccAq7/vQLsCewHDMUYQ7fbtWaz6VqtXJutCWt3OtJubBo7rPjMXsmMA5cz/60vJ3TuJzQEm1TiREJsRsKEElqrcEWfE0UJcz4P2Q9kwfvv/ZMBtD98I6XW+QXZkj0Q9uzdLZcgA8OkdYdMF5KakgwK1AWfPof7Lr52vJk27qufVq0PDKTltOoGBqo2OFi3crmszrkB4CHgAXpc5vpgSf/7MFAD9gVe0AcHYAlwK3Af0AQm+gDrVmV2H8i5ZtZpt9s2MdGwRqNJq9WUVqsZ9m1f1BqqxAr7v++laH43sWHEhhAaRhjzMBkJExNgJ/XhWUK+YDVx9FWy/9nbnN4k27oIQK39FUqLFmLhlX1beB+U67jMIRlIGiF1kApen8PCzy0cYZ91Dw2/dadp9ZqrVWtFrVZLa7UyWZaVRGQc+D2wiR73zARKqhqccwqIquKcmzSz14rImUC135uWmZ0nIrf0fw+oqjjnhJ54d4AGPU6dJSL7VqvVoSRJOlmWSKmU+KxSssVjH6zOa/5g8453nn8bzz3tEHzpDrTrECeQKnjBJSmhdQ+izwEWkNx/Oez9ReB924Jpmxxo91+wl0rjjc4vO7d3wQKu8kP84CyyIUHqgh82/ICQVA7k3m9evybstXb98FtnD9Xrrj5Qp5RlWq/Xnfd+AFgILANSVfVAHZjVf4E1EZlhZs8VEWdm3xCRD/QBfqSjIhtU9SIR+XszUxG5T0Q2quokPV25EZjsv4wA7AI838wajUaDZrujk+NjyWSzyZzJ/3pwTnrffPb5u79B2wsJEylxUonjkTAhxPENaOcURBIADfM/6bT+H7L/6Uv/KIBmiN1z/tWS3TqESM81JMlXSQb3QIYgGwQ/CH5QoDaflT+7cXNjYGLl4Lt3qA/W3WC9rtVqxdfr9QxIVPVeYKNzzoCOqjpVLSdJUg0huCRJusC4qp5FT7wPAlYCP1XVkf5zs4DXAbsCtwN7OOfO7nNiRk+EWzHGwntvzrlSn0N3APYzszjZbE50Wu1sfGKcZqNtu05+ffO0aitlj+NeSphcTGyATkCcgDhmhInlWJziutst/E1D9v2nIx/rmH08gPd+7ijSpc/BRnpW1+RWXGUd6WCGH+5xXjJo+MFhRpcu6q6+a2jJzHO65UpdBgeqbmBgwMrlciYiqqqLnXOFqk7vc4WPMRpQTZJkB1U9FEhF5Fwzu9DMbnfO/VBEXqyqrwGmHKW5c+4XZnatqr5dRA7y3p+uqh8DVFVvE5H1QAtwIhLo6dSNzrkKsEeMMQ0h5GNjY9rpFH5iYizutemTrjTvuS0G91iANcYJE544HoljQpyMxOZcsAN7SM3+AHHPhbLvP/9ua7zc47jP7OPEhz+KdcA64MIdSJKBBxFFpPcGigmx1Tc/f9G0syZrtZofHKi5en3AyuVy0gfveufc5qIo6mZWAWaZ2Rzvfdl7/3AI4SozGzCztqqeG0L4ELCPql4QYzzezFRVH1DVB8xMY4zHq+qFwHwzOyOEcF6Msamqg865K2KMK0XE05vaTDOzUgihqqojqnqD9z5kWZYMDAwmpVJGvT4gS6af1baHbzyY0FQwD67nzBVngMNz4xYcbOXHLMRzzEy2CyB3nfdicQ/8FOvMRrsQu78A2xWJYCaY6zGwxf1Y+quwbNrp19QHB6u1Wo16vUalUk5EZGdVXaiqQ3meO+/9BhFZrqqr6OnAE83sH/ttV4HvAB3n3Plmttg5d6Zz7sNm9i0zu69fvqWqH3bOnWlmy83sAhFpiMh/0JtgO+/9e1X1TTHGATNbb2YPOefGVbUEDKvqQmBOqZS5wcE6lXpdqgODlWXTP/Iblv48RePeOOt5wrUvpZrvDt3/7WMxS9zi/+aezx2+NWSPssImeqbY4j23XJDSeszvBAJODFHBWcrIA1c1sr1zN7DHjqVKhUqlQqlUcsA8M3tQVV8MNEVkjqoGEVkLPKCqVwEvA3Iz+yDwG+BMEfmtmV0hIifHGM81e3T8Z+p3jBHgTu/9h4qiOM4591ERuTKEcIb0JCMTkSuAGWa2v3Nujpk5MxsFEhFZ7ZybWyqVHq6pOrQaJuPOcxvNve6sjy2+l+Gdd8EkIAJ9LFHWYFMLokXvN9vzQWCLE2ILgPbA53bS7qrfi3WP7l+6GvxcJPRG4Kwn5LE1l/FVu63e4fM31CsV6pWKZVlm3vshVb0S2BBjTAG890PAAar6ahE5EjjPzOohhLO89xeaWQ6caWZnAS/vA3Wlqv5eRFqPAbEmIkeIyCtCCAeKSEdEPqaqfw/MVdXTReRCEXHAe4B6COEqEbk7y7LNIQRCCEWaprO894eWsmyTxuhDCG7NzH8s77X+jBcyML2AsBIxQ0xwKgTdCcl/h9kRwAJh/fds4blz5aAzVz+aA7vtE527fi7WXz87/wCwO+ZAVIgFuODZuOqmkfrrJirV+k5ZkkiWZWRZtqOZbYgxHglUnXOJiKwMIdyRZdnVIYTXmdl6EXm7qq52zn1BRD6gqv8CnAtc65z7sarua2avF5GjeQyJCH3R/IaZLXLOvSHGeB498f+AmV2oqqu89/8nxjgmIrPSNL0qhDAjhPBiM9sdiCGEpvd+JE3TOTHGDZVyOSpUNtVe/fMZI9cNMn32LliMmBnmIs4ghnshHtHrybU7Iq9/A3DRFgDNEL1l/U6uUhzRN8wbUD+vF8PAepecoHEandburbkvv7mSpZTLFSuXywnQCSFc1xezIefcc83sOOCQoig+18fgy2Z2gZl92cyON7MvAb9wzl2vqqfHGKfW2rmqLnTOPaiqK1XVJUkyD9iD3grlPX0wNwIfU9WXmNmXzGyVmf1cRN7rnDtdVS+MMTpVfTcwA/gVsFBExsyscM4dVy6XnRmxiGqTw6/cYcbqKw9nmo6CbEREURFIDPW7IGETyAwIL9PO+oZZ7516gLOP/budTZfuIXp3FT89Q9yvcaUhpNTzKLuy4TJlcmLZWPqi+2P9wIFqtUq5XDLv/d5mdqeqntLXQaNm9gBwrIisMbN5fZ10sHPuJ8C7gbu9919X1XeZ2dH0ph8Xq+p/A8tFZJr1RObFIvICM9vVzB4Efq6ql5rZXSLyfOBvRWRXVf2EiMxxzh3vnPt2jPEdgJjZcF+kZznnvuGcK6vqwar6ehG5XUSeZ6YbBcOMxIrx20v5is2UXA0NPYesRgfqIf4Bs5l0H/yDWHUZq45eec63/jDpALTg1c7dNouox9Nafh1KgKRnrhWPakKINZrtlzSnv7ZWq5UlTb1kWVYG1hZFsczMFpnZ61X1VBFJrfeKvm1mL+nruLkhhKPN7MNmdngI4Twzu8Y59wHgWjP7sIhcaGbvV9WXqGpZVVv9UlXVl6rqaX0996GpZ/v68jwze4GZfTiE8BpgjpmdZWYvCSF818wwszSE8E4zO9HMVqnqMhFZm2VZ4n0qWVay1ow31Gg0DydaBTMH3qHiEGeoy2kuv4YY3wy3zUL1WOjLq133ritxP3w+2HSgQTrwc8p7DeBqDl/ueVxi1o7Nimza5VNFqVqlkmWSpulBqvrrT3/603bTTTed6pwrPVZ3/TWRqnZf/epX3/ye97znZzHGwVKpNEtEXhVCuL3b7dLpdGzmio9XZKBb4PIKoQXSNEKrS3dJh2LytfRiFqMWTvmDe+m3X5WYne30+kUbnFkvCC38L0U+HdZ2KO9uSMxw0Wh3xyanvXHCe79TImLee8ys1O125998881HOec46aSTfrd06dIlCxYsWHDvvfcu2n///fdutVqNPM8LYNqvf/3rI733d5xwwgnjU4MaGRnZuHHjxk2zZ8/eYfr06dMvvfTS/VV12pve9KbrZWrSvhWJCHfeeWdz8eLFr5kxY8YtL3/5y1t9cOyBBx5YMn/+/N2yLMtGR0c3XXHFFUclSTI8MDBw1THHHON/+ctf2hVXXPGyer1+/ymnnHJkURSrsiwrpWlqeZ6Lc07Gh49bOty4ZJB6UcXFnh+gvcbQfAbGlcDrwaabdcfMznYJt66Yha2+A3hLr4tuBGQIbWe0V7Yp7xlJY5mQPjfUD16YJok453DOzVTVmycnJ1/kvXdFUXROOumkF8cYJ0XkkBNPPPEgM/secBpwu4hc8etf//rI4447bvyEE07YDNwAvA04cqt535L/+Z//WTk5OZmedNJJP6PnsgJIY4xVYHfgqGOPPbZ26qmn8sY3vjE/4ogjqsB/xhhf6r1/N4D3/lxVPfG6667b0O12hy+++OJ9yuXywAknnHD9qaeeuujHP/7x604++eQlIvJKVf2ZiMzy3m/IshJh2iE1Ri/dn8I2o/lGOg8NQLeKCuDWYr04l0tX38rNuoOjU+zpdHHSW2EAKiWE0PO2FTW6K0qE8fWmyXBWqdfTNLM0TUVV91fVDVtzhqp+xjl3HHC+mVXN7FQz+5CZHaSqHwVYt27dGjN7jZmdr6r7hBC+r6qnq+q5ZrYsy7LEOSchhAtCCF/ql/PN7BwzO8HM/tBut7/Sr2uVqh5iZuc7514FnA98N8Z4ppnNz/M8AmRZNg04X0SOPeWUU64WkTkrVqy4sq8bVwP7eO/FewdpdQjxMwgTG2g9tAMxr6BqGBGTdAtO4QFH7ua7qLoXrjHvEQBtGmopph6LghZCc023M/yCr5mZgk2tCBpm1th61aCqJ5vZ9WZ2DvAZoGlm58cY/11V/y/ATjvtNBe4S1VPB74FvBG4EDhTVY9xzomqmpn9j6r+SFV/FGP8jZnd1Tcmx1er1dMAhoaGZqvqN/ov4D5V/ZCqvkNVvxljvDTLMm9mOOcuNLNPm9mNr3zlK1+oqvHKK698oZmpmY2LyIRzzkTEvEinW33ORbTXdqEbUQUjwUiINn0LTtaYi9meiWg8ACkO6GPQQaRCtBwfCyIlEEOHO6jf1bmkSJIkAENmtjaE8KrR0dHvAh/pc+FewMMxxt+IyDkicq2q/peIvK//tlm+fPnyGOMxwIV9Sz1mZpc75xYCRbPZfDO9KcjuZlYDMLMNZrZSRH6rqqsnJiYAzldVAd7br2d1COHMNE33VtW/FxFijIv6n2c6537rnFNVPRxYd9ddd80xs/NDCMc659aratk5twFI1dUXEJM2lnchRlwUMI+TKpCjZEjYT0PsJBJ1fxwHA2ByD6KG8wENAWcZBYKUM4b2ayeJK8eolqZJbma5qh5YrVbX98FLb7jhhi8fcsghpyZJsjbG+Enn3Dn9acyXVRURef+ee+65B70A0b/EGDc5514A/G0I4c0A1Wr1rna7japuvadwd9VHtkEPDAxM9EV4tYicEULY0Xv/9yJyboyRGOMX77vvPpfn+SnOObrd7qdKpdJbzGxP4JMzZsw4ft26dTNijEc65w4ErnbOdfO8GEqSxJLpB25ktFzDaUSDoNERDEQdjvsxDgQ7VFRDglgZo95TZPogJlUsRpCIRkEAqQ672ryuiQQRSVV1DzObEJH/k2XZJ/uK21988cXv74vyHqr6MTMbT9O0VSqVjqHn9OTyyy/fddWqVfckSXJ4lmU2PDxMjPFmVV3TbDZHNm3a9Gag+pOf/OSHSZL4iYmJep7n3YmJCdm8eXPsdDph06ZNOwMvufLKK1/5+9///tA8z2tFUQB0RCTz3n8QwLmesynP83enaTrovf+AmV04f/7862666aY9RWSWiLwjxniqiOyRJH5pURQastkxteowRW6g1tsVZgZiRHsIOBBjEI2VBNXe3kUAtSaQoma4QsEJFoQ0rbq0hjmX9yTKhoHRWq32yRUrVnyn2Wx+qlqt0g9R4pyT/pywBAx1u48E+WOMu91yyy27sR1Kkt7y/PLLL3/L9u6ZIhGZ3e12Z2/93LZo2bJl//2c5zxnLvAl4L4sy+7tdDoHxxg/MzAw8KlOp7PUzIaT3to+NwYMyUpYXiBqRAOHEdWDTiJTLkHFoYVsUYxCCwgQlRiFEAQtDEmHVBLnvS9UNdCLV7SA3efOnfuqkZER1qxZQ6PR2OJ6+muiJEkOFZHXmdmFIvK5I488UkZGRkoDAwOvA3YVkWY/LlOYmSVpDciGevtrQi/Or7FvPGg/YnCDc72NnvRKdEqkidDEaKK2DmMN4hLvk2az2eyISINe7GIDgPd+N4CiKNi4cSMPP/wwo6Oj9EXqr4IWLVp0D/B3RVG8Kc/z7+y9995Lgc7atWt9/5YNwKoYY8PMmnnezXGuRKBFpAk0UBqYTqDoFrxMSTDskTCJ1VCGCQgmZg4vZoZnMoa8UqkMls0siTHuY2YPbauzMUYmJiaYmJggyzJqtRq1Wu0JReyZoKIoaLVaNJtNfvCDH5RGRkZeOmfOnN/ssMMOyxcsWPBGEVl37bXXPnDyySc/L8Y4R0T2EZGFIhLE2ySiE5jMwBCi9QL+Ig7byotvWALxkXi/yRCQRMU5jFhYCXGaxDgeuk2DctL39TXpBcCfkPI8J89zNm/eTJqmU55rSqXS0w5oCIH+epZOp/MoCdiwYcPJ3//+9x/3zNe//vWFJ598MmY2ADRU1RVF4V0+TmahEYxpBBVBAog6ByJWe4ThIglqG3CyCmwepkNmKIZEwUV1DlTF8gZx3GBGGmN0fZ3x+B34j9Bm59xD9BjdqequRVEMbz2oJElI05QkSciyjCRJcM6RJAkissWCAqgqU/NIVSWEQFEU9L3M5Hk+NbnfFq1yzo1OratjjPvTC8azadOmV/bvmWNmDeecxBgTjZMSi9CIQYcR5zykeFUiINQQAZEHzeLaxDTeLUYKzEPcAWLcY6ZmipppjMFI8tEGzeXW9TtnWZYCrFfVA+jtBngUOefuEhEdHh5ePnPmTN2wYYMbHx8HWNV/BmDL4J9BUu/9LWaWzJ49e/nAwIB7+OGHa51OR60XtdsdyNevX39zrVY72Dl3dwghiTGaH1+UabGpFQszEg3OgSgizjnE9u8bkdscdqczC/ejyeL+Mm6WYQ3MopmoBefMJOk21laTxuKKmbrY83aPmlkSQrgeoF6v/wxARO4WkearXvWqHdI0PcE5d2KpVDrhqKOOmiEiLefcfc8kYluT9/7mUqk0/qIXvWh/7/1JaZqeOG3atGOPPfbYrohMAmumTZt23ZIlSxaaWaqqm83MVFVKnQdrne66ajRJXHSiEcQkGjaO0lvOkSxB7QHnE1lCHFyLWc+3H2l5xKtapqYuRpNue6ySFSsXhKCxv05tAHS73dWPEZ3k2GOPnT4yMjL3C1/4AqVSic9+9rOMjIzsfNRRRw3S24X1bJysXGlmpec973kvnT59euUTn/gE8+bN4/TTT+fee+89/MADD1zhnFvfaDRmttvtrK8eGj3VECzLVy0IjfGKRiOqOtRSU0vFaE3hRJi2nsKWJ2xuL9fa7Nc7t7HXtLNGjOwgaoWpYEoSY3emaPeAPG//CkoVEcmdc4QQ5l166aVXNxqNI5MkuQ6we++99yWHHXYYt912G7vvvjs33XQTCxYs4NZbb91XRK53zt1mZjOfcPhPkURk0+zZsx9cuXLlwcPDw6xcuZKhoSHuuusuDj30UFqt1jELFy5cVhTFXO990teteVEUxJi3he4+MXYjgDnUjAg4orWm9nJo2GGmm2bLEnnrzRP6k8MPe8QS41EwkwTFFIsaRIr25qt8vmY8uHlV770lSbIaOOKFL3zh/y5evPhKgOc+97nV733vexx++OEsXbqUiYkJ5s2bx2GHHcbvfvc7jj322MV33nnnI6HUp2nSLfL4PVJHH3307BtuuIHjjz+eK664gvHxcV7xilcwOTnJ9ddfnx1wwAE3NZtNt+uuu74GeKgoCosxGq1VY3lr9CoN7CjO1KI4ExEUxZNN4SSUXiwvu+YT/bCbbRLldoSDMTnSO1seogU1cTEXb2YyvvaOscHB31dG0zdrjFG893cDx+yyyy4bP/OZz5yqqqgqt9xyCz/72c94xzveQQiBgw46iO9973ssWLCA973vfe+cum/Kom5tXacAfeznFEBbfzrnEJFHfe87erdY8F/96lf86Ec/4rTTTuOaa66h0WhwzTXXcPDBB/O2t73tnd1u99uqOlNVfwVYu92VOe3rapMjCyei2lwfxXDOnMTgRQSTl4OB8QczVkJvcyPnvGnuJDI+ihWvAKaJ2kIzqmoiqhBUpNMZr8/ace8j1snzljrnvHMud87tF2Ospmk6bGZOVVmwYAGXXHIJeZ6zdOlS1q9fzx133MEZZ5xBrVZ7FHjbA3Lr348t2+Pex3KhiDBnzhyuuOIKGo0Gq1atYs2aNaxfv54PV+O33AAAECZJREFUfehDJEkSut1uDZihqre3Wm2X5+3unPy3x2548Kpu6sV7QROPpIL3XkYxDu8teev/Kjrjl+dctnpF71W1uFnjzvVHnIV+rSBCRDDBDDWl3GmM/LrUWTbS6XQkxqiqehuwT7fb/Y+pAe68885cfPHFpGmKc45SqcQFF1zAnDlzHgfSE5W+W2pLeTLPPBbsww47jLPOOot2u02e5+y1115cdNFFZFlGv8/7qOqt3W5Xut3cyvmDGzutkSs0UlLFMHEoiIlhbJjCR8PcIWLj1p4o90kvPegaSe/bC2wOcLsZY50CaRdYNzfJI6gbWL3LIe+euyh9+4ZSqSKDg3UnIieq6n3lcnm3vsf4cQP+YwA8lgufSISfSGwfW7z32/s93ul0NojIfFX9z0ajRbPZtP35wZyVt/zbKomTcyspVkqFSoaWUkSEGcCBmKy2uN9id9LCl8NWu7NU9UKsdHEf5YMFNgjgpLcBFpCiPbkTYbKgvXp9nnes3W6rmd0I7Nduty/dlsg9FpjtgbctDvxjL2B79W2v7anS6XQuN7MFwPV5nlur1RLXfXi9FRPtojM5B3D9bXwighNYh3Fgb65culgtfmEKty0A+qHWFZrvNG/LPEddI3WGiLkE8JiKt/TB2340viD9/X7tdtva7bZ18/xhM5swszfGGK/bnu7a3oC2J7pP9P2JxPaJ9KeZEUL4dYzxFBEZy/N89cTEpO902rpP6boDlt98adNjPsE0wSQRIxEDle4ULhp3nu/Xt696HIDy6qVd1Asql/ZMdXy7F5ssiUURvDcRr1i3NT5DWxsmKvnitZONhms1m1oUxdVmVu92u0NmNj4lftsb2JPVgU9WBTwWzG2B2O/ThjzPZ5tZmuf5NZONhmu22jpkS9fE9sho0R4fRhDvRRMxSxLDY2OIvq0nmXIJKm05bWn3cQACOHFna5hzX1+MM8ytS5yId+AEBMErsui671b3Gbjn2G6n02w0GrRarY6ZXQUc0Ol0rrZetOsJOWFbYG5Ld/4xffpk2zGzTp7nd5rZc4HfdDqdvNloWrc12dqrfs+rF1373YokvU2ECeC9+FTEsGQjPbcfxLlLXJJ/+lGYPcr0n3LPerS8D/DbHhfaWxOxsVKCeYdkHhMvRAvDS2/58Y0H1X9fGZ9o0Gw26Xa7m+htAH99nuc/2NoIbP35ZET6sRZ4ayCfTB3barvb7f48xvhK4A+NRmt0YmLSJpsNe/70m+tLbrrsRrUwLe0fB08F6Z2rtzGI7+jpPq6MoTRfTlo6sl0AATq+/U+az76h/1AVlZg6o5xg3uNSj6WefHz9kj1orrCdSsvWTUxMyOjoZtrt9lLgTjN7ewjhB8CfxYl/zpTlCUpeFMUlZnYicHur1Vo+OTnpGo0GOyVLVkvzIR1bt3yPzBNTJ5Y5LHGQelPE5T1JBHTObb7onvFYvB4HYO3kVWuIpRSTb/aXLSd6WJQ6c5nHSg4p9xqS+67+9tCe9QcPk+66NZOTEzI6Okqz1VpsZjer6luLovjZ1jrxyXLlE80Dnwy3TX0C62KMv1PVk4GbGo32srGxMRkd22x0143sOfTQYXf+5t/qpQQyJ5qmWOKQLDHxxiLM3tTXfV/TIknlnSselxXpcQACuEp+Tsx3HERp9Pz/7kWZp1tySEkg8bjUiROscsvln1v7kl2Wvrzb2LhhbGxSxsfGtNlsPqSqV5jZ60IIK1X1uq3r/1PB/BNBm6Lr8zzfqKqvUNX/nZxsPjw2ttmNj08Smps2vnju4iNv+cnn1qVi1VRESg5KhpQTXObIUXdEP/bRiPnsHZzaJ7aJ1bYuykkPt73xbbR+Zu8N2P6ibqycQrmMlZ1ZKYVyIi6VOHzzjz9/99ELlh8dWhvXjI6OsmnTJhsbG5sIIfwXsIOqHhRj/Da9I1mPom0BsD0An+iZrWg8hPDdEMLzgel5nv98fHx8cnRs1MbHN2unuWHkmL0ffMXNl3/+LtEwVErFlRJcmpiVykgpRcXcJrB9eqJbP9OL/5q8c8U2T7E/4WnN8J2df+iTtQKc3If7KyGyf7ONNbqUOoXQbFtoBaJKZc3hJ33igF89sOPVOcNzhoYGQpqWy/V6RUul8qCZHqGqS4CFMcZTVHvO2a0t67asLvC41cTUiuIxn+qc+w/ghc65nUTkd3mej7dardhqtbLJZlMzHXv41c/Z8MqbL/nMIrHG9EqCr1TEVVOjVibUM0g89wFTx14viWHHkLxz9du3h5Hf3h8A57x++i9jrLzV+ZZgzACe6+B3HqYhaIw4J+JMkbwIQyvuvHryZS9//i6tXB9YuSFMC0Xs5W2KoeVElgCY2dFmttjMfk7v8M1g//qWds1sm56XKRAfc20N8J/0gvgvBO4piuKOZrMZx8YmmZycYPPmUXYb3LT+pXtu+ptrf/iJEbHujEpKUstEaplRKxNrKaTCCoR3AB6RJTGfPekle/s5Px3bbuzhjx64bn9tx92yrPigS8b+AcgQNqP8ohuZ28zxrQ7SynHNDtIulE5wxaEn/PP6WJnDT24faJfSSlKtlsvV6oCVKxmlXgCpDOypqrur6m/NbF2Mcb6qvlh7Z+keJbZbr3+dc8E5d4OILPXe7ygiR3rvV5jZgzHGVp7ntNtt2p3cmq2m73ZbjeOfN1nz3TXx1h+fv2PJaVYtOStnSK2C1lJirUxeSlmPcQwwo7e9b+gifPlf5e1rthm+fdIAAoRvzXytSHcv51rn959aCdzcDcxsdPCtHNfuIO0ca+UaWwEGZu+16pDj3vc3Ny1Nfr1oXW1WuVz2pSyxUqki5XK2dSQuU9VhM9vFzKap6gozW2NmDVUt+qcvMxGpi8iOwK5JkkyIyEOqOm5mRVC1kOd0Ojndbod2u0On0427zypWHLlv53X3XfWD69ctv3V+NcPXMmeVBKplQqWEq5eQUsZalBfSOw2PhuqHTct3J+8e+dUfw+bJZ+345vR3kbTrkE8dR1iF8LsisGujQ2xFrNUmtrvUmwXdboHP1RUvPOmfNyYDO02//BbuGu9k8yqlMlk5w7uEUlYy55A0TcQliTkRw0xxHouxd2Cot3PT+kcbxEzEQIIG0SISo1qet6UoAt08aLvb1uGyrj/hMD0gTK7ZeP2PPj+zlGhazoiVBK1lZJUSRb2CVlMk9ayldzJ+DwBi9gG01pV3b3xS2Yz+pLwx8RvDn3RZdwzrgyhsxvhJMPZq52izLVmzwFq5SbdLaEeNndyZlOutw97wwU5anz39ZzeHO9dPMCvxaZp4j08z0iQlSz1Kz/XhxHdxRFR7ESvnPIqPUTPV6LwX63aDKLEXEy6ChVDkc4Z15G8Pyw4qJtZvvOm/v1ixTqNaTpRSySXVFF/NROslpJwY1RKWeBZjnIAw1BtP9gGKclXevfmzTxaTPzlzUfzawBnOhwSXn9dPDpZj9i1DDmp2oR0Iza5qJzhrFfhuR5NOQdENTpPKwNiBx5w6MXOXfY9YtiZcef097e7IhE2XLMlSvDjn8IngncfMgllvQ7JzIoqkGsRUC4kWpCiCodadPuw2vXi/cmXBTslRIyvvvfauX/37YNGdnFbNVDJHUi67WMmIlVSpJs5XMqRWwouzuzB5J5BhqMbkDGflivzD+JMG788CECB8tfZO8cVOzsd/4pF8pz9CGOjm1DoB1+yStgq1dk6RF851g/puTtE10iLSGNpx95EDjjrFTZu928taOXcvebizfMWabvfhTV3f6UI3qqC9o6WC0ywVyiXYeUYp7rZTWpq/c3WPWsYBm9c9ePU9v7lEx9Y/uEOaUMs8oZSQVTJXZF6tZ22dK2eESkYsJf2NU0I/LwKjhPSLEb8i+YfmD/5ULP7s7G321cphEXuv98XeiL2gf3kxwu8N269VENtdF9sFaadQ6/aSDaXdSMgLfKFoEUhiJCcpjw7OnDu+497P1xk77pqV6tNr5drAoE/THUSchLy7odOcnOg2Rpub1q3M1y26zU1sXD1E6ExPElLv0MzjspRQ8iSlhKKSkpRTJ6WUolZSygmZiNyH8VKmMs2Z3BhDtlyRf83e17r1z8HhKaW/m/jywIy65N+XJP4B9JGljsiPMTSiO3cCRTt32im01A3keeF8oap57nxhWsRA0lEwJQQlMcNCz502ldqk109BEwERJHEEcSQlB6knJN6lmdOYlpzLnMZKQpZlrltJ1ZVLpB63CiPF7PgtfTT3KYv+b0TKb5F/HN/852Lw1BMwXobX9dmZmJrL9K3Agv5fOSr/jmdGVJ2bF3Q76nxRqHZy52LUmCsuj06jqu8qgjmiEtTUmEqF0vumgDlx4h2Jd2qJgHcuJk592ROT1PlSopomzpW9xiwl896tQumAvZlH0gcs1sJd4oTAxnCenP3Udko8bTlU7SvMN/NfFW9XAJ9iKmVJL/vkDzEM0V0Ldb5bqObRuagaikBWmLMQCKAuGAFDowKO3gpASbwDBJcICeI08SSJU8kceZKSpGCl1EnqNWJuBYLD7C1bsmBCC+MTMcqrfIjvlQ+y/OkY99ObhNaQ+K8ch+OdPnG3KXwco7xVY/eqyY3iqRk6xyJZUFeEqC4oFOYExaKh9JzaPSMiGOLECw6HpKKWeMyLI/XqxVMIbq1Fmk7scIP9txphxymfiUGfD3zL/3/84ulMifzMpEH+Bmls8yaMU8y535rnNOnP8rdqeA3I1eKsbSolB4NRdFgMb0Y0wcR64mXSSzggggeCw40rTIizrqlUwF5msNOj+gArPVykhR6t8P27q1x2yHt42vcdP6OZzO1sXBjmKODDqvxeEjfN4ANP0JlRRG43GBdljN5OWDCrmWNYYAizgw2mP0EdXzJ0s1NeivDZZDNXP1U990T0rOXSty8wsyuchXMrTLjgmWhDjDNQ3a1kfEr+iY3PRBuPa/PZaGSKDKR9AZc47x6KulUuwqelbrnIqe5c+SdOFJ4+HffHaJse6WeKBKwyyVtDoQca/Eb7qbSfarHItVbovpUB3vxsggfPMoAAcjahW+KNVlhDlZVPGcDIWjFbF5U3yTNgJP7oeJ7tBqdo9F84wMOpivwjsmWS+6dSMLUvpsJ3Bz7CdpMkPpP0FwMQYPyznByUHXFy4Z9VgdrpzjE+7aN8+2nu2pOmvyiAAJvO44tmboNh5/1pT8qnPTpj+se3nRjx2aK/OIBmyKbP8FMzN6bY257MM+LkMjGtzQy89pmc4z0ZetaNyGNJBGtv4k2gczVy+5MwHHcRdVoROOkvDR78FQAIMO+LtIm8zYndr8bodqcrRkuwG73jXTudTeuP1/zM019chLemtWdzpCkvir2EZI8jBx9xCTfNOYvfbev/vwT9VXDgFM05m2sMgiinP477lNMd6F8TePBXxoHQW+6tOYsfFsrDpnyof/GiJGHmzp/mrc/2SuOP0bN7CvpJkICZ4+2rjF8G5RcmDDrHvjt7Xv3XBh78lYnwFMnZhOg5SRxF6hmhyUlyNs/o2dj/X9LKT7D/yo+y31+6H09E/w/wHJVcjfUH5AAAAABJRU5ErkJggg==\",\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABdCAYAAAAyj+FzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAH3gAAB94BHQKrYQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHiczZ15vF1Fle9/a1Xtvc98780cEjJCAgkgiUwiIghCgqLIQyK2qI0D2g6PlmfbbaONCmo/habB4dF+tBX0KdC2PFGZB4GEgECYIQmZp5vc+Yx7qFrr/XHODSEkiDKuz6c+Z9+z9zlV9T2ratWwal3C6yh64YW8Y8Ex4431M4yhOQAtVMUBTOgRQRGEWvtBlJnRgGJABSthdIWHrIyI1l9y3339F154obxedaDXOsPGr2+anFL2TgXOJKZWEIYP5oslL0z7EtE8Zj4M0O49f5qGofKAF32GRTe1GnWTZOkR5DUi0muC0Nxaete7el/L+rwmALdde+34nOcPgei0ILK/j4rlLmbztyBMfkUyUGwT8f+ZNGojWeLeBchvjOR+Xvngqf2vyPe/iLxqABWg/p/+YqFR+WYQREsLXeUuMH8WQPhq5dmRVMRfUR8eqquTt7Din7rOOXsFAfpqZPaqABy88spjlPhfi8XytSbKfZxAB+3l0ZSZ7hXD6wkWCAggClURGWJSggUAUjivokRIoJpq6gkkyl5miOJYqNq9VO6xer3+UxfHp4P9l8Z+8pPLXum6vqIAhy+/fLYXXFksdd1go9wXQZjyggyJH1HDDyEIQ1iawMZAjAWTsWS55QHHbEREGQwPABAYZhLxzjDBIpOcQBx7BwhUvOtDkiXk/WGqcugeirbJxc1LGvXaqY5x7sTPf37NK1XnVwTgg1deGcwcHvkWOKpXuiqLiPjI3XIZJBv91lub59CORWBVAysmDKyQ8QgsQGSNsakaUhAYIAPqlE+hgHpRVeMB730IFcfOK8RbSVPHTghZCsn8IJI0hk/fA8WYXYuhovfVa8O3eudy69eWLzjsP87NXm7dXzbA6oXfnJNBflwaM+4uJrpgt6/fTlFwC+dyY7w1Fvk8KAwYHChHRsQGAVvrEBgSsGE2DtYATAwFE4MBQAUCgkBU4D3EewtRD3WK1FmkzsE7gstI00zQaoEynyFNNkucLCZg+q6lUpVLRoYGj1KWv53wla+sfjn1f1kA+750wblBYGcXunpOJcUBu3zrsIbBryhfnGaiyEghIoSRahiAcgEjyCkCqxwEFsY4BCHBEAnIIzAEsGEGRDVgYgXUiQAMcfAeEDXwqshSFe8t0syxcyRZTIgz0TSDacYkaapoNb2kySaK07MAVEaLqIRnGkNDv3ferR7/rxdd+ZoC1Asv5L6R+k9yudJTuXz+YgA7O3EOwquQjyoo5POI8oRCBC7m1YcRKIgIUUgcRSqhVUSRARtvrGEPkiRuVBsDw83B3m3Ot2KqDQ8TAJR7utXkcjpm4qSgOK4nn88XK1BlOC8iziBOPWeOkCTkk0SROqU0Jm00QEkKtFqqzVZLG406vHxol6q4pNn6XBw3jh23Zf3ZdN11/lUHuPpzn4t6Mr2h3DX2T8T85eeoYjuKuT9QobwPFfPQYp4oX4Tmc0AxD+RyanIBxIZk8hE8sx3cuLnv4ZtubD774MOz01bzQI4KjwTdXRt57NhhDYO00FXOAKA5UgsozUIZGOjOhkemSdI8NMwXnt7vsIVrDl20uDhu2tRxRtT5OCZOUvFJqhTHhFYMbbSIkpai3oSvN0Ct1lY0mqeAMHFn0UUuqo0MHDkU0Kn7X3FF8qoBXL34c1HXxNYNlZ5xawj0qZ03DN3I5UqMYqFgSiX4UhEo5IkKBUUhDxTy4FweEobF4R19g7f+6D8a29etPz6cPPGWniOOHM5Nn1qKyuUKk+UgCMSwigoLMwQARNr9ocucEUC9TzWu1WqNDRvrw8sf6HHbd7xz0uxZd5z0iY+VK+Mm9HCa1aXZJG01iZJYfbVJHDfV1BvwtQbQbDSlVsvB6+JdQHxvZLDvwDq5d8/86U/jVxygfu5zUV//4I1dXeN7QXTWzvdN+GNTKU5DpSJUKYKLRaBShi8UCaWCUr4Ijuy4NY8/9syNP/rPg6mYf3bSu9+zpTJj3/FhaG0YRWRsiCC0yFkLgAWgzFgSMkYBQL0n74iZJRDxnDiHLM3Ue4eklVCaZVlt3fr+3j/8YYrWG7NOOfeTT86cP+8AybIdaLRI63Uy9ZZKowodqZOv10G1WiLVxiD77CO7VPPqkaG+aSMjAyfvf+ONL0kTXxLAa9//fvN2p7+rlMdsYDbn7oQXhj+kSnkmd5cJlS5QpSwoly2KBUGpRFTIj92+YcP663/4g/2CSZMfnnrG6T6sdHUXopByuYKGoaEwDBGEIaIwJGOMhGHovKfEGPVBEGUAkGVJoEqGCGGaJoH3npPUiXcpxXGKJEmRpC3EcapxbWR463X/bZLebQvf95nPrpm4777TpNUYQD1WrtWdr9dCDI8IqjVItcpUra3WNPvMzjqpfH9kZOCACQGd/FL6xD8LUAHaccq7flEuj9/ARP+480YuvIzK3fO4uyzo6iLT1QXpKkMrZZhSyWTQiddd/r1n62lMsz/+sb6ouzKmmC+gWCxImMtTFAQmn89REEQuzIXKABtjhIgUAAPIOgkAAnQMlarCe8+i6tMkYeecbSapxs2WZGmszWaCRquOWt/g0Iaf/WxiJcxl7//8Z+ayoldrdaFaXTEyDD9cI1NtiBseUNtobHDN+FPP1Vkuqg4Pzph40w1nv2yAW4874dxKqZyzJnfZ6Hucz31fyuX9TM9YoKdC6KkIlbuYuyuiheLEbZu3rL3h5z87aNJp77lp7PyDpuZLZZTyEQqFvBaLRQRRzufzeVimoANsAMB2AFsAbAbQByDZDWAEYAKAKQD2ATAZwBhVhXMuSZ3nZrNhm/U6teIUraSl1ZGGDj3xWO/263+76D0f/chjEydPmaWN+nYdqTKGa0B1WGRomDA8QjpYfRZZ/HejdXRZfF6tWfeT77rte381wIHD3zpfQ/s3xfKYL0GVAQA2+iF3lWfpuDFK3V2Erh6Ysd2qlRJToTD3jzffcseza9dMm/s/P7clX6wUKpU8R/mCVkpFLRSKEgTWWmstgEEATwNYC6Cxh3IJgKM6fy9HWyu1c4861wUAswDMA9DtvXdpmvp6vW6arVQazRparRZqQ0Mjq//9+/vvt/9+a4898Z3v0Li1CsNV9cNVz4ODVoeqIsNDHsNDG5G5tiaqukZ96JLM61WT77/nqb8Y4JPz54djw8LN3eVxUxS6PwCA7a+op9JF3V3MEyYQuiqCMV2M7m4gCg/6f7/573uauUJj9t+eXSiXyzaXK3JXuaiFQh6FQsExcxnAJgDPoK1xhHbTpA6g7g6UgwAcDmB2pzhrANwP4KkO7CoA34HoOq9jOp/b13ufJEmi9XpDq9Um4rhOtVrVr/np1Y1CKy68532nH0NZ+gQGhtQPjxCGhlX7Bw2GB70OD4/A65JOvqtGagPbJrK8kx56aI/TPrM3gF8ZO/HfugpdG9W5U+EcyPmnqFioarEYULkCKhWEymVGpUxgc9A11123ws7cb+P+HzprXHdPt+0qV1y5VOCuroqGYRgZYzIADwJ4Fu2mWQHQIyIREUUAciJCRJSo6qeI6NsA7gZwO4ClqvppIrqpU7xIRPJElAfQg/YSWQJgG4AhZh5rrc1HUZgGATMRGRuGKM87yA5v2Tz02N33NOfPPeBQUfSyS1nTDEidauqIUie+Uffk3AQ4NzYy9prBZv307/bt+N1LBrh1zpwDQoTTAzIXtKdO4jSMbuJysULlippKCShXiIolImsPuf6m3y+LDpy7ZeYZp0+qlMvc091FpVJJy+UyBUFQYeanADwCIBWRkIjGiMg+qjqWmaep6nxVPY2IjlLVJ4joMACnAzihkxYR0TCAR1T1M6r6FiIqEVFFRHKqWlFVUlUhohjAWiLKjDEzoyhyxhhlMrCWbGn//UrVoaG1Ty9dGs+fvf+bSWgL0tSqy0BxBmSppSx7FnE8H84zvBzjnLvhf47r2XZpf//AnwWoAFXHTfivclSeR0RTAYA4uJIqpamolJkrJUi5ApTLxLlw9u0P3HdPOnnS0KwzzpjQVSlTsVhAuVxGoVAoMHMOwOMiMkBEkYgAABMRqSqJSAqgn5mfVtVFALYC+Bu0jchVAG4AcAeAJ1R1tqq+T1WfJaJ9mPknABqq6gDEABLvPYjIEFFJRFJVbTDz5CAIDDO1mNmoshRnzOgeWr9+oPfZZ9fOnDr1MFHpJ+cUzqv6lJH5IpL0VqgcAQChCcstFy+6ZKD/Z1/7cwA/PWfeCcWwMMhsP94mqiu4XAJVykzlElG5i6irCCrku9f2bnnk2aGB8rxzz43KlQrKpSKVyxUtFAqWiLyIPKWqCYBJqlpBu5/qEZGJzDybiN6jqkd77+8hoveq6nYi+g4RBar6QQDvBPAOAAuY+W4APyKiBao6A8AtqvpFAAtFBERUZOYKgPGqWlTVHiIa6qRyEAR5a61T9T4IIi4fOCdcd+/SfJGwprvctQ9EEnZi1XmFc6Qu60Ka1gGaDMI+AfFlQ2PG5i7p37F+V168u/YJ9KvWRl/a+UCY+xNyUai5HFMxUuSNIoyQthK6f+XKhQed9/fVUqlIpWKBS6WSz+dzQfurcC+AQe99WVXzqtqtqhNVNSKizap6u4iUVLVFRBc5574IYI6IXOK9f5+qiog8IyLPqKp4798nIpeKyH6qer6IfNN73xCRCjPfCmCt954BdAHoIiIjIkUR6RORZUSURVFki8VykM9HWiyW+KC//3zz/pXPLEySRCm0RiIryAVKuZyafJ45Ch4Y5WBN9EURf7HuZnifp4F/N3f+WwthfoTJvL/9Dt2ihahiKmVoscDIFxWFAlEQzvvtI38anvPpTy/vmjC+p1AqoburolEUBUQ01Tl3D9rW1DNzQ1VrzJyo6j4AFgFYSERLVfXdAC4HsICI3gvgSWPM94joZhFZq6pxpznfraq/Nsb8UUT2AfBhZh4G8FMAxxPRLar6BQBv8t73qeomADuYuQmARKSMdvew0FrTMIYVRAAQFvaf89T9N/x26gGTpkwn7/uQesCnUPHkY99NLlkNYH8AFct6SX+lB5cO9m/eCXZXgF79N4wJp47uvpgo2CxhYYoEgSIMlYKANLB2Ze+W28v7z0m7pk6elM/nUCzkuT20w1Tv/UYAbxWRhqqOrnhscs6tIqJbARyvqomq/j0R3QbgAiK6Q1VvJqKzvPcXqT5//2f0b+89ADxijPmi9/5dAL5MRLc4584H4IkoJKKbiWiMqh4gIlNUNWDmfhExxpgtzDwlDMMtBRHyzvvuqVPGl/af9ejqbVvs3DFjp0kQOAojFROQKQQqLtymSdrmwflPESenAjjxBQDXzZ8/iV1wO4CLAEAJd4kNpyCygAmI2KgGBkjdlCd3bJ+54NOfWFbI5xFFEedzOW+M6QFwFxFtUdXAew9jTMV7fygzv5uZ6977bxNRwXt/gTHmUlV1InIBM38VwDs6oG4RkbuJqLkbxAIRHUdEJzrnDgUQM/OXReQTAKZ0NPBSImIAnwJQAnAnET3mnBs0xkBVM2aeYK09wlo7kM/nDaA44MNnRw9dePFb9ytVMmbaAGtgQqPehIAJ9oFmfwTp20E4gNn+cu3MgybOWvfE9ucBDBJ5X7EY7dynZWOfhjEzjbWkAUOJiRRmxY5t901bfHItly9MyefzUiwW1Vo7SVV3OOcWoz2wtcaYDQBWiMidRHSqqm4jog+LyBZm/i4RnSci3yaii1T1Hmb+tff+QACnEdFJ2E2ICKq6XVWvVNWVzPw/vPff7IA8T1UvFZFNxpgPi8gIgAnOuduDIOgGcKyq7uu9Z+993Vq7PYqifYhou4jXLPOFKSce9/tH7vtTeUHPuGlK7MFWOTAiQQAT8FPe+bcDQCksjvVu5HQAPwQ6RkQB8mtXTwf47e3GQn1gM1WtgbckwqywRN6l4zYn8dsnvfWt46PQahAEFIYhq2rivV8G4Ceq+v9UdbWInOyc+4S1FqoKVf2Bqh6qqr8RkW3e+8tU9XYi+rKqHui9vwzAuWhb6UcA/MY5d7lz7nIAv0F7HNkD4FwiulRV91fVL3vv7/TeXyYiW4jotyJyqKr+H1UFM5Nz7hNEtNg5t0lE7iKiX6vqnUQUW2tNEIQU5iLd9x3vGLclTY7zWdoDqLbrzGBr4GH3VcWAAgDTcbJ29b6jP6xBW99nGJOfEYy0ijSmO1TCLRREPchFZIKANQyFQqPPpunq8C1HPjl+3oHlKMpRsVgQZj5AVR/z3p/V0egBVV0JYDEzbxORfQGMVdXDAPyaiD6JtrH4oYh8TFVPQnscdzkz/5f3fnVnnDiLiBYR0WGqKqq6XkRuNcb8ynv/eGew/W4imi4iXyGiyQBOZ+afiMhH2nqBsdQ2FhONMVeKSAzgMBF5LxGtYOZDiagPquS8mrReWxFv3jw4hrlIaQpJM1LvGN4ZdemDrDRG1qx9VLys+TvJNl8OjFgASGBO6Db58ar+fbxu3dUye78WDBMRVNgAAguHYJ1Lj15w8onLC4UchWGo1tqIiLap6urO2OwMVd3CzFd0xmY/VtVvA/gCgEtFZDERfUlVv+WcewuAW4wxfxCRt6vqlzpGAp0BN9BeUACAQzoJncEyVPW/jTF3O+feTUTfVFUB8CXn3BeIaKL3/nxmvkRV/5GIvq2qARF9QlWnA1gqImuMMbOCIAicc1k+r5h16ruKDz348JGzDe0gIAUzQExEVmBMitVr7obXsyObW5e6+O2Av5oAYC3s78YVxhypinEA1blS/i3PmlnWUtFSPgcuFCjOBc3l3RXz5i9/MQnDkHO5HIVheLCI3P6Nb3xDly9ffg4zR7v3XW8kEZHklFNOuf9jH/vY74IgKFhrJwE40Tn3aJIk2opjevDib+WPGm6lhTTNS6OpiJvQetPrug01P1x9L0ELRNgx0By4byb8aVYBXg+qimIcACj0FsTJOOzojbk40wMSiM90HezwtFNOrhtjJodhKNZaUtVCkiSz7r///hOZmc4888w/rl69etWcOXPmPP300ysPPPDAuc1ms56maQag55ZbbjnOWrvitNNOG2Fuj+H7+vr6+/v7ByZOnDh+zJgxY6655pr5ItKzZMmSezvN73lCRHj00Ucbq1ateteYMWP+dMIJJzQ6cPSZZ55Zvd9++80IwzAcHBwcuPnmm0+w1naXy+XbFy1aZP7whz/ozTfffHylUnnmrLPOeluWZZuCIMgZY5SIyDBj2knvfHbDdb8pz3U+r+otvCayfYeXZnOcQm8BcJoqJgCcKDzbTcCknA0fBnAWAKjyDiWUtZmEfv2mxM6a2VAbdG8L7SGHHzTv0SAIgPZofJyqPtJsNt9sjDFZlsVnnnnmMara6PR3C4noJ6p6HoCHmfmmW2+99bh3v/vdI2ecccYQgGUAzgZw3C7jvjU33HDDxlqtFpx55pk3ABhdUg+89wUAMwGcsHjx4uI555yDM844Izn++OMLAK7z3h9rjPlkB/JFInLm0qVL++I47r7iiisOyOVy5dNPP33pOeecs/K66657z5IlS54mopNV9XcAxllr+7xX2ufNC4sPXH/DvLnS6JPEx1i/UaXZKrR/S9422qtYGz603mUT2AP7Rhxyu89VcOADYnWqHuLSfLpxY5dWa9vZmO6wUCiTseC2+swTkY2jlSciiMjFqvouEbkEQE5VP6mq56vqId77LwPAtm3btqnqqar6HRGZB+BqEfmCiFykqqvCMDRERM65S5xzl3XSd1T1a6p6uqo+2Gw2vwcAvb29G0XkMFX9DjOfDOA7AH6mqhcQ0aw0TT0AhGHYA+A7RLT4Ax/4wB1ENHnDhg23qSpEZDOAedZaMobI5HIltcF4DNd28IZ1OfGuCCiUycP4YJRTyCEE2Jc9zFwY3rf9NqDe9DjhQAUW3oNcipH+HcmEgw/5PhEnDIWIKIC6qtZ362POArCUiP5FRL6lqjVVvURVfy4iPwKAKVOmTAbwsHPuCwB+5Jx7P4BLAVwgIouZmbQtN4jIr0TkV97721T1MREpiMj7SqXS5wGgp6dnkohc2fkBnhKRL3Ys8JUicl0QBKYzhLpMVb8BYOlJJ530NhHxt9xyyzGde0NEVG3rAKVgbk6cP/97IwPb1WWO4T2p91aFAxUaM8rJGp4CmDkWoDcTuON+RqmSlgyJI/Uq3nhKM9SisKX5cJYxrNbamjFmnKpuc869s6+v72cA/rGjhXMAbPbe30ZE/wLgHhG5jog+O6qp69atWy8i7ySiSzuWelhVrxeRx4wxSaPR+EC7K9GZqlrsXO9Q1Q1EdIeIbKnVagDwHVUlAJ9WVRDRJufcBcaYA7335xIRvPerOv3ol9FeFgPaq9a9jz766CTv/XcALGLm7QBCIhokIOJibkY1CJs5X/fshYyqcyQGRBEpUkBDEM0jaGYB7KekC6EEgj7JAOC9aHvnQSAW/cVSuO/cuYn3PmLmnDEm7UzDFlQqlb4OvGDZsmXfO+yww86x1m7z3v8LM39NVd/mvf9+54f77OzZs2eoatF7/x1rba+IHAngFAAf8N6jWCw+2mq1SER29SmcucvQBsVisQ4AW7du3UxE56vqJBE5tzOrEefcZStXruQ0TT/IzGi1Wl/P5/N/Q0SzmfkrY8eOPaO3t3ccgGNEZIGq3sXMKRH1QFXGzp2bbSyWypPTXqgXdd6BvRdVZEr6FBSHMnCYgBMLIA+lCgAo6RZRhFAFeQ8IQSwQR2FPYZ9JW4MgSK21LCJzRaRJRB81xnwNAIwx5oorrvhspynPEpF/BlC11jaiKDoZnd73+uuvn7Fp06bHrLVHhGGo3d3dEJGHsizbGsfxjoGBgTMBFK6//vqrjTFBtVottVqtuNFooL+/X7Msc0NDQ1MBvO3WW289aenSpUfEcVzy3ouIxEQUGmPOA4BRS++c+6SIVIwx53nvL91vv/3uXb58+SwAE4jooyJyjqrOtNauIiJXnLoPJ8Woy2cZwYuyqIoqoEgFWMvAoarUDaBgAfCo96sqWiA15L1CmMApICDJh/l8qcTGGFFVj/aUaqRYLP7L2rVrf9xoNL5eLBZ3aggzEzOHaO9VVJLkuU1+7/2MBx54YAb2Isa0V9h+85vf/Pk9WaKJrVZr4iisUWC7y9q1a389b968aQAuA/CMtfapOI4XeO8vLpfLX4vjeA3aa4gCQE0QqURRDmlKgEK8AAqCihK0iueGV8yA2tGOkYAUIIEoqfckzpPLHBAEFY4iEhFnjPGqOhbt3bGZ++6778l9fX3YsmUL6vX6zqWnN5JYa49g5lNV9d9E5FvHHnss+vr6cpVK5X0AphNRA8BY770AEJsLSYytqMtUUwd4bbMDRBWNUV6AWn6e87WSV9KmGtRhUGdwPYCpE1srzmVE1ErTNFHVLd77AQAwxswEgCzL0N/fj82bN2NwcBBZ9rKdP18xWbVq1ZPe+49nWXam9/4/DzzwwGcBpNu2bTMA0FmE3UpELWNM3RiTsA1CgOpgqpNBnRk1z9QU2J28aFT7dr5BmldFyQIqIPKq5OFh4evqfaiq+c48dC6AjXsqrPce1WoV1WoVYRiiVCqhUCigs+D6mkmWZWg2m2g0Grjqqqui7du3Hzt58uTbJk6cuHb27NnvJ6Kt995779NLlix5E4CJqjqHmR8CYLMkSQP4qgrKBJAwhKBgJVZyFjs9jwEreE4FhajIopRAGSAGkRG1CJwfcnEqlMtZIhIiqhNRcc9Ff07SNMXg4CAGBwcRBAHy7QVYRFH0igN1ziFJEsRxjDiOn9cCduzYcdbVV1/9gs/84Ac/WLFkyRKoahlA3XtPzjmbtVrMiWs66BgQiIWcQpVZQwJ17eQFwBLQC9UNIEyHoqJGYwhIIO21QvbepGktHhpyQXeFOyvNDeCFHvi7yBAzb+zkwSIyLcuynl0rZa1FEASw1iIMQ1hrwcyw1oKInmcQRGR0TREiAuccsiyDcw7OOaRpOrrcvyfZxMyD1PbBgfd+Ptq+NhgYGDgJAIhoHwB1dFQrHhlxuSyteUg3g4xv93VKYFJomaCA0hoCtliBPi4EQ8B0IZ1LgscZUKfwgIoQo7S9v9nYtDGMpkwxYWhtZ2B7SCfT5wkRPU5ErqenZ924ceNkx44dPDIyAgCbReTg0edGK/8qihhj/qSqZuLEiWvL5TJv3ry5GMexV9UxqjoTQNrb27u8VCq9mYgeFxEbxzE11m8Mcn39Dc8QFaiFAkSkKoZID1YlgOQhQB9lBT2tKqsAgBTjhaTmSb0C6kDGiQa8dWuhsWZ9TtVb55wBMKiqxjl3LwCUSqXfjsJj5vqiRYsmBEFwOjOfEUXR6SeeeOJYImow85OvJrFdxRhzfxRFQ0cfffR8a+2ZQRCc0dPTs3jx4sVpZ+q2paen596VK1c+pqoBgMHMeyYiaqxdVwy2bCtnQoEA5Nu+TJ6gI6o0BgC86rMCeoYZfnXm0+0Ytc3CDXiygASqYK9MNFwrNNavnZ2mKURERaQOAEmSbN1t2GIXL148pq+vb8p3v/tdiAi+/e1vo6+vb+qJJ57YjfbK81/syP1XyAZVjRYsWHDc2LFj81//+tcxffp0nHfeeXjyySffsmDBgg3MvKNer49LkiTqdA11FYFzHsn6TbN4qJYnBYmCFQjEU6BKzVFO4tMdgF9rCVib+Oy00OQAAMTUVFEVpUyhUKhFko5F4g5Mk+QOIgqIKGVmOOemX3vttXfW6/XjrLX3EpE89dRTxy5cuBDLly/HvHnz8MADD2D69Ol45JFHDmDmewE8rKrjXk16RDQwadKktRs2bFgYRRFWrVqFSqWCe+65B4cffjhardaihx9+eG2WZVOMMRYARCTN0hQuzRLN0nk+i58ASAOwCOANgcHaVGlb4KbPxjtgjd0fqK4Uf/ROWyxqASYlsVBWBbwCCPv778x6dwzQPvtMMsZoEASbVfVtRx111E3PPPPMzQBwyCGHFK666iocwXXn3QAAEZlJREFUe+yxePbZZ1GtVjF16lQcc8wxWLp0KRYtWrT60Ucf3Wl+X6lB954WXk866aSJy5Ytwwc/+EHcfPPNGBkZwTve8Q40Gg0sXbo0nD9//vJWq8UzZsw4RUQ2dgyVtjZtGgj6+m9X8EQAQlBWKBFYSBBqh1Mq/m3zgQvabrNAnwIPEHAEgBMIspJUIKTkARaFMQ89OlJbvjw/5vTT1DlHxpgnACyaNm1a38UXX/wxEYGI4IEHHsD111+PJUuWgJlxyCGH4Oqrr8acOXPwmc985m9Hnxu1qLta11Ggu7+OAtr1lZlBRM+7Hp3OjVrwG2+8Eddccw3OO+883HXXXRgYGMD999+PBQsW4Oyzz/5okiT/KSLjVPVGL6KNRoOaD64o24cfq3nIFEOkAlIDdYAnAb+jw+sBAtYBnV25v4OphWyHmPidALqgtEIIxbbnIkOg5KrDJT3ggLebgw9ew4aNtTYlonne+2IQBN2qyiKCOXPm4Je//CVEBKtWrUJvby9WrFiB888/H8Vi8Xnw9gZy1793T3vT3t21kIgwefJk3HzzzajX69iwYQN27NiB7du344tf/CKstS5JkhKAsSKyIm61qNVspcnd95yst92RWMAYYjEABYCxsIMKfQsAOPGXpz77w/cg6xkAArj7W65VHs1cGNsZpBYMQKAgiFIevX23tTas64vjmFqtFlT1QQBzkyT5xWgFp0yZgiuuuAJRFIGIEEURLrnkEkyePPkFkF4see+fl17KZ3aHfdRRR+GrX/0qms0m0jTF3LlzcfnllyMMQ2RZ9gtVnauqf0rTVFutBK11m/pNb98tqhIqoKTC3LbAqup3jPJpuVaXh/sTsIun0dMwf+zJd+0PxWRVPA7CjhSglgIJhDxAaSm/OffZT0+17z+9t1AscqlYZCI6Q1WfiaJoWmfF+AUV/nMAdtfCF2vCL9Zsd0/GmL39PRTH8QARzfYi1zXqdbRaseh//fe41uXf326ayZQA0BwMAlLJA8SKsUp4EwhbBlsjz86DPw7Yxb1NgEuc91e0C4qDFboDECK0zY4KyNdbU2iknqT9/X1JHEur1VIRuU9VD0iS5Jo9NbndwewN3p408M/9AHv7vr3lPZriOL5BVfcDsCxNErRaLcRbt/XpSD1zzXiSgtgAyvAwbSPSq4Q3AYB6fzmA/z3KbSfAEP7melqfNrppQqKtAIAhUAiAWD1BbO2XvxyJ7l52QL1eR6vVEieySVWr3vszvff37K3v2luF9tZ0X+z6xZrti/Wfqoosy2713p9FRMNpmm6u1eucpqkU7n/wwPov/m+DAGsgQgAZAhkoWDQZ5TKY1ueuh7/9BQD3BxLfNtHXdHxAPgyiEduZzzJAEFI3PDxO+3aMYP3GvlqtybWRKrz3d6hqMcuyblUdGm1+e6vYi/V7f8n13mDuCWKnTL1pmk4CEKRpeme90aBGKxa/ZsN237d9OKnWxrQdKEm4c9qbCcPKdLa2rcEvAG2c0nZofz7AdjOWC0fSxuiZCMuCHQYg204IIEoA9f7kqlLlqZXvTONGrd5ool6vp9r2OD04juO7te3L8qKa8FIMyksxIC81H1WNW63WU0R0sIjcFsdxVq/VEdfr9a6nn17c95OfFRhCFkohFBZqLKAQ7kfHi62aNtcmkG/syux5AA8GtntxBwB0BwAo0YcD5WFDpAYEA4YBQzPXvf26/75vzP0PlhuNmtZqDWo2m4MAHgLw3iRJfrWrEdj19aU06d0t8K4gX8p37CnvJEl+h7YP4oOtOB6oVqtaq9do3EMrituvuW4ZMt8TgikAwxBgicDKwyD9CAAocIsTN3th22N2zwABIIb8r6G0vqzd4jUnLD4E1HS2OgJAQ6KkuXrlfn79Rp9fs663Xq9ptVbzjUZjjao+AuCDzrlfAHhFNPFlal6aJMkvVfUMAA83m821tWrVjNTqlHt27WbevJmba9bMMgRvALWAsBIFgIA1BRAqgKG08TBBzt+d1wsALgS2irhAIT8CFFCcYYFVAUHzgIYAWRKyUF37o590j9u89ah0247eWrXKw8MjaLZaq1V1uYj8TZZlN6jqyN60cW9a+WLjwJeibaOvALamaXoPgLMUWN5KkjXDw8M0ODSk0rejf0LvjiPX/OA/ihaAhUoHIIekxJCVpLqkzUB+KOLsfOAFUZH2eNDmQ9ClcG5J3uZmKBBCKWcNDQsQCEQ8wSiIRMT0Llvef9CCQxZsjIKnHbikIgKgGQTBJlU9xTm3GsBqANN2b3Z7et2TMdh1/Lf7GHBPY0IigjHmHu89EdERAG6O47hvcGjI1OtNifsHBg5cv/HYJy765gbrfaVAxCGBilDNEWyOTaxCbwJhHIGqQ0ltex/kcz9re9/+eYA/BtynYaqG6HHDZhEIE6D6EClXAHgHYgAsBPLqo833P7Bm4cELjt1A9GhGWnaqEOdbzPS0MWauiExX1Z9re+Qf7KkP2xO43QHuCmhP0Dpz4CERuVZVTyYicc7dPlStJrWRmtZrVY37h/oXbu094bFvfXuFSZOxEZGNFDYCfA6MHDGp6nYiHA8Aqc++lIn//RGQPUb32OtZuR9C1nxc/GcjGz5JoIMBmk+svyPQBAACUqiSVVJIlhW3LLt/5eGHLzx8o8NTKUkh88555wNAN1pr+1T1VBFZx8w3icjB2j6a9bwmt2uzHJU9QdqLBgoz/1xVJxDRUQD+2Izj1fVaLalXq+FwraZZ//DWI/r7j3/4m998gprNSTkgyIE4YmgBLDkiWKUniXAOAAjwi2ra2Ocg+Ev3xmmvAAHgH6A31lz6oZzJEYCxUD6YCHczoUeU2DMMQCBSylzWtfHOu2tHHnXk9DjLHu/1bqzKzj4sZrarARUROUnbHq2/Q9tFrmtXiKPXe1p5GZ2K7QZvC4D/ApADcDSAJ0RkRa1Wy2rVBtXqVQwODMvkoZGtbxoZPuyBr3ytj5JkfJ5gQmWTJ0IR7AsEWKb1qvhIh8uq4WSkVYJ+6N/30HRfEsB/B9zHgWVO3fjIBAsIGhHRDIY+xNAygRVQgjBDlcW7YN0dd2bzDj7YTjXWPJVltVbqOUvTXOYz8c63VGU1M9cBHKKqU1T1NgB3S9uzfho68/Pdm+0uyRHR3UR0B4DtRHQgM5dUdV2apk83m83myMgI1RpNHR4aMLVavX5stV6sbNpaWP71i4qBl2IEaF6ZCyxSAEsemgXEW1RwGkGLANxI1riaVL4yp30YfK/ykmImPApzap7t3EKQ+067ctigwP2xYlwq4AYLN6AcgzQW9S0oeubM2fTmv/v0kY8Q3bUxF3bnCpHJBYFEUZ7CMEQYtnfjmDnsaOE07/047/16Vd3S8RZIvPdgZgugQkSTmHm6MWaYiDZ2oKejO3Rx6rXValAaJ9qMWzohTre9FXTy4z//5dLtDz64fx7gHLdHE3kYXxDhHINyxFsVeCsU+wKQetb6p1T844fA3/jn2LzkqB2PAOeUOSqHQefoP2EThP6YkUxvgnwLoi2QT1RLTZUkUTXehukxXzp/MJw8acyt3j1RZTOhkM/bMBeQNYHmcyEAAxMwhUEgaLurdcJmAUTtU/LS9kfU9jUABrIkJS8eBGiSJJRlmaZpqtV6S3oEAydZO6+1bVvfsv99yVjj0jBH5AsgHzKFecAVwFIAyCi2EeMoKGYBQJrF5zUlSQ4G/s9L4fIXxY15BPhqV5AfsRx2INIQAdd7yP4tQJseQQvQJpRarC4VlRQQU+5qHP2Fz6e5CRPG3dGsr9geBOMtIQzDnLBlCkyAIGBSJTWGoKoZGePEOQ8AbK1R7y0RWSfKDEWaeiiJpnEK5zJkzmfjVftOyOXfnG7v237vv12Wk1qtEAKImGxOyOZBvgClvAHyIDWglar0PwjtfjiV9Lx61iq8CfjWS2XyF0cuegz4+zyHYRTkvwmAFUiJ8WNRPTSGaqzwTYEkDI2hpuVhHSFLoGq7K4NHfvQjtfEHHHj8mlZ828NJq9HnsnHGhNYGhgwD1rYNhaq6dgwZoDM5sCKs4jLy4uEyp+KzrDsIB95aKJSmBdEJ2598+s4HfvaziqtWe3IgChQ2b8hHUJ8TQp5h8gREIEtKjwP4KLU9yKSZxV9IJPmL4P1VAAHgUeAjAduppaD0v9CJd2oIvxKlcgJfjAHTFLIxqcaKLGXlTGBa0CxTsWK40TNjZt9hH1hiumfMeEcs+sS6VmP1hjh221KniXrK4I2gHXiH4cnA+DwZnRQEPCOfs7ML+f0j4gMH1qy/88Hrfikj69aPZ9FijthZUBAxfCQkOYYtClHI6nNgH4AalrThFWd2CAwOp41/F3FrDwV+/pey+Kujtz0EHMXgT48NS3NBGI0XuAqge5TkgFhJEqiPgSCBaiJwKSRogbxTNY7IZ6rGkWYmFw10T506MnXBm3X89Olhvru7GJXLlSCKxgNAliR9rWp1JBkZafZt2JBufPghHtmyuUviZEygFAREYlXZErkIGoTgNMewEYhCIMsBlCMERvkpJX07FPsDACnuG0rrazzk8gXAn/4aDi8r/N2TwJgU+HlPWHqQiL/y3B39NROJE0yJiVwM0VQ0TIE0ZVgH+EzEZKAsgwYegIdmClivnCl5B2KFSHv8xWyhQlBjLElIgCOQDUFqAR9AA8vsQ4ADgc8BgWVKc2DOqQbM2KSqAYHeN1pCUflaNa0fTsCHDgGG/loGLzsA47WA2Q/4Z8sWXUHhQ9o+nAwFUkB/ysAYrzQ1IU0cqYmVxAGcifoU4IwhHmIgTI4FIuQEUAWI2lNGKFQIHZcxVmuElVgQgL0RmBDwAZOxgIQEEylcpBQxY6MRJI4weo4PAJ5pZM1rMnHuTcA36bnjZH+VvGIxVB8HZjvghyVbvCkw9hsKLXRuCSn+rzIEqtMzgnEKTQnkPJwzCJwCHuqkbTUcAeIERNSeAajCWoZqe2XcctuqBJahgUdmGUEAeEswgcIR0XoVWGqD43ZFqZn49CtN11rkgE8d3g7487LlFQ1CqwCtgDmVIH9bDIsPWeJ/1vYUa/T+kwq9j5WKRDQ5UwmFkHmAPRSOQOpJhSHtlcT2fI6gCiYigWGjsAplkBoAAWAMOBPVbSBtEOhotCMZjVYwdioXN9LGmwX844Xwv38lQyK/KmGQHwQCMmYJRD6UM7nbQms+D6V9n/cQ6VYAdwLUIiBSRQVAt5IaArwHgbQ9jFESNu1ItKbtLIFhIlQ73UQOwAlQmrRbzTaIc5c3fHyiMv9Cvb/2sOdicb1i8qpGMleAH7T2BPL6T9aYu3Im7CHQeXsvDQ1CZQVAI6QY0fZ0DqRaVEIXoF0gXgDVMXv7CoVeFvt0KPP+WGPoWwucu/Pl9nMvJq9ZLP0HgXFg89U8h+uZ7SWvRh4i7vyGZNNZ3DcOA171MPDAawhwNL8/sfllzuQ2M/EL9hdejojq5bFrTT1M/RmvVtj3Pclr/t8c7gRswdjfFzjHoOfCh7wcIcU9dYlj6927Xo1+7sVkz0d7XkU5HnDq3ftjadWVdNPOU6J/bSLd1pBWb+bdktcaHvA6AASAo4Bq5s1Xmz79tQKpoN3L/6XJAy7x2VXkzdfe9jJmEy9HXheAAHA00sdJ6QFR/Ye/FmCq+g9edeURSF8z5/Xd5TXvA3eXZRxcam00zMDukeX+nHwj88nYt/jnIvC+HvK6A1SA7jPhb4wJqtSOofBS5NpMsuKtLn3Pha/iGO+lyOsOEACWAXm1we+Ywm4iLPwzjz/mJNuSufT049vHJl5Xed36wF3laKClLjhbJHtEQdW9Gw2qZ97f5505940AD3iDaOCo3GNzx4HxVlZz0Z7ui8o/KrLlxzr3x9e6bHuTN4QGjsrbXHwXRJywnP8C7WP5AkHkjQQPeINpYEfoHpP7hRrapEr/0H5LL2fR8W/z8d/gNZymvRR5IwLEnYBlW/i9gJiACNBYXfOU41/ExeL1kjdUEx6V4wEnLlxCkCogfeqaZ74R4b3h5d6wNP/esDT/9S7Hi8n/B3LrBEUxxEM2AAAAAElFTkSuQmCC\"],\"useMarkerImageFunction\":true,\"colorFunction\":\"var speed = dsData[dsIndex]['Speed'];\\nif (typeof speed !== undefined) {\\n var percent = (speed - 45)/85;\\n if (percent < 0.5) {\\n percent *=2*100; \\n return tinycolor.mix('green', 'yellow', amount = percent).toHexString();\\n } else {\\n percent = (percent - 0.5)*2*100;\\n return tinycolor.mix('yellow', 'red', amount = percent).toHexString();\\n }\\n}\",\"markerImageFunction\":\"var speed = dsData[dsIndex]['Speed'];\\nvar res = {\\n url: images[0],\\n size: 55\\n};\\nif (typeof speed !== undefined) {\\n var percent = (speed - 45)/85;\\n var index = Math.min(2, Math.floor(3 * percent));\\n res.url = images[index];\\n}\\nreturn res;\",\"strokeWeight\":4,\"strokeOpacity\":0.65,\"color\":\"#1976d3\",\"mapProvider\":\"OpenStreetMap.Mapnik\",\"showTooltip\":true,\"autocloseTooltip\":true,\"labelFunction\":\"var vehicleType = dsData[dsIndex]['vehicleType'];\\r\\nif (typeof vehicleType !== undefined) {\\r\\n if (vehicleType == \\\"bus\\\") {\\r\\n return 'Bus: ${entityName}';\\r\\n } else if (vehicleType == \\\"car\\\") {\\r\\n return 'Car: ${entityName}';\\r\\n }\\r\\n}\",\"tooltipFunction\":\"var vehicleType = dsData[dsIndex]['vehicleType'];\\r\\nif (typeof vehicleType !== undefined) {\\r\\n if (vehicleType == \\\"bus\\\") {\\r\\n return 'Bus: ${entityName}
        Bus route: ${busRoute}
        ';\\r\\n } else if (vehicleType == \\\"car\\\") {\\r\\n return 'Car: ${entityName}
        Current destination: ${destination}
        ';\\r\\n }\\r\\n}\",\"provider\":\"openstreet-map\",\"defaultCenterPosition\":\"0,0\",\"showTooltipAction\":\"click\"},\"title\":\"Route Map - OpenStreetMap\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{}}" @@ -169,4 +169,4 @@ } } ] -} +} \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index cbf5883659..d9183c1cb6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -178,7 +178,7 @@ export interface MapImage { update?: boolean; } -export type TripAnimationSettings = { +export interface TripAnimationSettings extends PolygonSettings { showPoints: boolean; pointColor: string; pointSize: number; @@ -203,7 +203,7 @@ export type TripAnimationSettings = { labelFunction: GenericFunction; useColorPointFunction: boolean; colorPointFunction: GenericFunction; -}; +} export type actionsHandler = ($event: Event, datasource: Datasource) => void; diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index e614c80455..b8b1d193e4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -29,11 +29,17 @@ import { } from '@angular/core'; import { FormattedData, MapProviders, TripAnimationSettings } from '@home/components/widget/lib/maps/map-models'; import { addCondition, addGroupInfo, addToSchema, initSchema } from '@app/core/schema-utils'; -import { mapPolygonSchema, pathSchema, pointSchema, tripAnimationSchema } from '@home/components/widget/lib/maps/schemes'; +import { + mapPolygonSchema, + pathSchema, + pointSchema, + tripAnimationSchema +} from '@home/components/widget/lib/maps/schemes'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { - findAngle, getProviderSchema, + findAngle, + getProviderSchema, getRatio, interpolateOnLineSegment, parseArray, @@ -43,7 +49,7 @@ import { } from '@home/components/widget/lib/maps/common-maps-utils'; import { JsonSettingsSchema, WidgetConfig } from '@shared/models/widget.models'; import moment from 'moment'; -import { isUndefined } from '@core/utils'; +import { isDefined, isUndefined } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; import { MapWidgetInterface } from '@home/components/widget/lib/maps/map-widget.interface'; @@ -117,12 +123,17 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.normalizationStep = this.settings.normalizationStep; const subscription = this.ctx.defaultSubscription; subscription.callbacks.onDataUpdated = () => { - this.historicalData = parseArray(this.ctx.data).filter(arr => arr.length); + this.historicalData = parseArray(this.ctx.data).map(item => this.clearIncorrectFirsLastDatapoint(item)).filter(arr => arr.length); this.interpolatedTimeData.length = 0; this.formattedInterpolatedTimeData.length = 0; if (this.historicalData.length) { + const prevMinTime = this.minTime; + const prevMaxTime = this.maxTime; this.calculateIntervals(); - this.timeUpdated(this.minTime); + const currentTime = this.calculateCurrentTime(prevMinTime, prevMaxTime); + if (currentTime !== this.currentTime) { + this.timeUpdated(currentTime); + } } this.mapWidget.map.map?.invalidateSize(); this.cd.detectChanges(); @@ -214,9 +225,15 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy } calculateIntervals() { + let minTime = Infinity; + let maxTime = -Infinity; + this.historicalData.forEach((dataSource) => { + minTime = Math.min(dataSource[0].time, minTime); + maxTime = Math.max(dataSource[dataSource.length - 1].time, maxTime); + }); + this.minTime = minTime; + this.maxTime = maxTime; this.historicalData.forEach((dataSource, index) => { - this.minTime = dataSource[0]?.time || Infinity; - this.maxTime = dataSource[dataSource.length - 1]?.time || -Infinity; this.interpolatedTimeData[index] = this.interpolateArray(dataSource); }); this.formattedInterpolatedTimeData = this.interpolatedTimeData.map(ds => _.values(ds)); @@ -255,7 +272,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.label = this.sanitizer.bypassSecurityTrustHtml(parseWithTranslation.parseTemplate(labelText, data, true)); } - interpolateArray(originData: FormattedData[]): {[time: number]: FormattedData} { + private interpolateArray(originData: FormattedData[]): {[time: number]: FormattedData} { const result: {[time: number]: FormattedData} = {}; const latKeyName = this.settings.latKeyName; const lngKeyName = this.settings.lngKeyName; @@ -271,10 +288,57 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy } const timeStamp = Object.keys(result); for (let i = 0; i < timeStamp.length - 1; i++) { + if (isUndefined(result[timeStamp[i + 1]][latKeyName]) || isUndefined(result[timeStamp[i + 1]][lngKeyName])) { + for (let j = i + 2; j < timeStamp.length - 1; j++) { + if (isDefined(result[timeStamp[j]][latKeyName]) || isDefined(result[timeStamp[j]][lngKeyName])) { + const ratio = getRatio(Number(timeStamp[i]), Number(timeStamp[j]), Number(timeStamp[i + 1])); + result[timeStamp[i + 1]] = { + ...interpolateOnLineSegment(result[timeStamp[i]], result[timeStamp[j]], latKeyName, lngKeyName, ratio), + ...result[timeStamp[i + 1]], + }; + break; + } + } + } result[timeStamp[i]].rotationAngle += findAngle(result[timeStamp[i]], result[timeStamp[i + 1]], latKeyName, lngKeyName); } return result; } + + private calculateCurrentTime(minTime: number, maxTime: number): number { + if (minTime !== this.minTime || maxTime !== this.maxTime) { + if (this.minTime >= this.currentTime || isUndefined(this.currentTime)) { + return this.minTime; + } else if (this.maxTime <= this.currentTime) { + return this.maxTime; + } else { + return this.minTime + Math.ceil((this.currentTime - this.minTime) / this.normalizationStep) * this.normalizationStep; + } + } + return this.currentTime; + } + + private clearIncorrectFirsLastDatapoint(dataSource: FormattedData[]): FormattedData[] { + const firstHistoricalDataIndexCoordinate = dataSource.findIndex(this.findFirstHistoricalDataIndexCoordinate); + if (firstHistoricalDataIndexCoordinate === -1) { + return []; + } + let lastIndex = dataSource.length - 1; + for (lastIndex; lastIndex > 0; lastIndex--) { + if (this.findFirstHistoricalDataIndexCoordinate(dataSource[lastIndex])) { + lastIndex++; + break; + } + } + if (firstHistoricalDataIndexCoordinate > 0 || lastIndex < dataSource.length) { + return dataSource.slice(firstHistoricalDataIndexCoordinate, lastIndex); + } + return dataSource; + } + + private findFirstHistoricalDataIndexCoordinate = (item: FormattedData): boolean => { + return isDefined(item[this.settings.latKeyName]) && isDefined(item[this.settings.lngKeyName]); + } } export let TbTripAnimationWidget = TripAnimationComponent; From d22209ed7304f07b5de94920128e669705d68ecb Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Tue, 2 Nov 2021 16:09:46 +0200 Subject: [PATCH 215/303] create relation rule node - corrected current relations deletion if selected, refactoring --- .../engine/action/TbCreateRelationNode.java | 65 ++++++++++--------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java index 5c06183106..28eafabfce 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java @@ -18,6 +18,7 @@ package org.thingsboard.rule.engine.action; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; @@ -69,41 +70,31 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entity, String relationType) { - ListenableFuture future = createIfAbsent(ctx, msg, entity, relationType); + ListenableFuture future = createRelationIfAbsent(ctx, msg, entity, relationType); return Futures.transform(future, result -> { - RelationContainer container = new RelationContainer(); if (result && config.isChangeOriginatorToRelatedEntity()) { TbMsg tbMsg = ctx.transformMsg(msg, msg.getType(), entity.getEntityId(), msg.getMetaData(), msg.getData()); - container.setMsg(tbMsg); - } else { - container.setMsg(msg); + return new RelationContainer(tbMsg, result); } - container.setResult(result); - return container; + return new RelationContainer(msg, result); }, ctx.getDbCallbackExecutor()); } - private ListenableFuture createIfAbsent(TbContext ctx, TbMsg msg, EntityContainer entityContainer, String relationType) { + private ListenableFuture createRelationIfAbsent(TbContext ctx, TbMsg msg, EntityContainer entityContainer, String relationType) { SearchDirectionIds sdId = processSingleSearchDirection(msg, entityContainer); - ListenableFuture checkRelationFuture = Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON), result -> { - if (!result) { - if (config.isRemoveCurrentRelations()) { - return processDeleteRelations(ctx, processFindRelations(ctx, msg, sdId, relationType)); - } - return Futures.immediateFuture(false); - } - return Futures.immediateFuture(true); - }, ctx.getDbCallbackExecutor()); + return Futures.transformAsync(deleteCurrentRelationsIfNeeded(ctx, msg, sdId, relationType), v -> + checkRelationAndCreateIfAbsent(ctx, entityContainer, relationType, sdId), + ctx.getDbCallbackExecutor()); + } - return Futures.transformAsync(checkRelationFuture, result -> { - if (!result) { - return processCreateRelation(ctx, entityContainer, sdId, relationType); - } - return Futures.immediateFuture(true); - }, ctx.getDbCallbackExecutor()); + private ListenableFuture deleteCurrentRelationsIfNeeded(TbContext ctx, TbMsg msg, SearchDirectionIds sdId, String relationType) { + if (config.isRemoveCurrentRelations()) { + return deleteOriginatorRelations(ctx, findOriginatorRelations(ctx, msg, sdId, relationType)); + } + return Futures.immediateFuture(null); } - private ListenableFuture> processFindRelations(TbContext ctx, TbMsg msg, SearchDirectionIds sdId, String relationType) { + private ListenableFuture> findOriginatorRelations(TbContext ctx, TbMsg msg, SearchDirectionIds sdId, String relationType) { if (sdId.isOriginatorDirectionFrom()) { return ctx.getRelationService().findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), relationType, RelationTypeGroup.COMMON); } else { @@ -111,19 +102,31 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode processDeleteRelations(TbContext ctx, ListenableFuture> listListenableFuture) { - return Futures.transformAsync(listListenableFuture, entityRelations -> { - if (!entityRelations.isEmpty()) { - List> list = new ArrayList<>(); - for (EntityRelation relation : entityRelations) { + private ListenableFuture deleteOriginatorRelations(TbContext ctx, ListenableFuture> originatorRelationsFuture) { + return Futures.transformAsync(originatorRelationsFuture, originatorRelations -> { + List> list = new ArrayList<>(); + if (!CollectionUtils.isEmpty(originatorRelations)) { + for (EntityRelation relation : originatorRelations) { list.add(ctx.getRelationService().deleteRelationAsync(ctx.getTenantId(), relation)); } - return Futures.transform(Futures.allAsList(list), result -> false, ctx.getDbCallbackExecutor()); } - return Futures.immediateFuture(false); + return Futures.transform(Futures.allAsList(list), result -> null, ctx.getDbCallbackExecutor()); }, ctx.getDbCallbackExecutor()); } + private ListenableFuture checkRelationAndCreateIfAbsent(TbContext ctx, EntityContainer entityContainer, String relationType, SearchDirectionIds sdId) { + return Futures.transformAsync(checkRelation(ctx, sdId, relationType), relationPresent -> { + if (relationPresent) { + return Futures.immediateFuture(true); + } + return processCreateRelation(ctx, entityContainer, sdId, relationType); + }, ctx.getDbCallbackExecutor()); + } + + private ListenableFuture checkRelation(TbContext ctx, SearchDirectionIds sdId, String relationType) { + return ctx.getRelationService().checkRelation(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON); + } + private ListenableFuture processCreateRelation(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) { switch (entityContainer.getEntityType()) { case ASSET: From e5ff6aba163ab5dd48700c32eb225e06c37cf8f6 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Thu, 4 Nov 2021 19:59:24 +0200 Subject: [PATCH 216/303] added create relation rule node test --- .../action/TbCreateRelationNodeTest.java | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java new file mode 100644 index 0000000000..88172bdaa4 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java @@ -0,0 +1,184 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.action; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.common.util.ListeningExecutor; +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.TbRelationTypes; +import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.relation.RelationService; + +import java.util.Collections; +import java.util.concurrent.Callable; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class TbCreateRelationNodeTest { + + private static final String RELATION_TYPE_CONTAINS = "Contains"; + + private TbCreateRelationNode node; + + @Mock + private TbContext ctx; + @Mock + private AssetService assetService; + @Mock + private RelationService relationService; + + private TbMsg msg; + + private RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); + + private ListeningExecutor dbExecutor; + + @Before + public void before() { + dbExecutor = new ListeningExecutor() { + @Override + public ListenableFuture executeAsync(Callable task) { + try { + return Futures.immediateFuture(task.call()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void execute(Runnable command) { + command.run(); + } + }; + } + + @Test + public void testCreateNewRelation() throws TbNodeException { + init(createRelationNodeConfig()); + + DeviceId deviceId = new DeviceId(Uuids.timeBased()); + + AssetId assetId = new AssetId(Uuids.timeBased()); + Asset asset = new Asset(); + asset.setId(assetId); + + when(assetService.findAssetByTenantIdAndName(any(), eq("AssetName"))).thenReturn(asset); + when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); + + TbMsgMetaData metaData = new TbMsgMetaData(); + metaData.putValue("name", "AssetName"); + metaData.putValue("type", "AssetType"); + msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getRelationService().checkRelation(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + .thenReturn(Futures.immediateFuture(false)); + when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) + .thenReturn(Futures.immediateFuture(true)); + + node.onMsg(ctx, msg); + verify(ctx).tellNext(msg, TbRelationTypes.SUCCESS); + } + + @Test + public void testDeleteCurrentRelationsCreateNewRelation() throws TbNodeException { + init(createRelationNodeConfigWithRemoveCurrentRelations()); + + DeviceId deviceId = new DeviceId(Uuids.timeBased()); + + AssetId assetId = new AssetId(Uuids.timeBased()); + Asset asset = new Asset(); + asset.setId(assetId); + + when(assetService.findAssetByTenantIdAndName(any(), eq("AssetName"))).thenReturn(asset); + when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); + + TbMsgMetaData metaData = new TbMsgMetaData(); + metaData.putValue("name", "AssetName"); + metaData.putValue("type", "AssetType"); + msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + EntityRelation relation = new EntityRelation(); + when(ctx.getRelationService().findByToAndTypeAsync(any(), eq(msg.getOriginator()), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + .thenReturn(Futures.immediateFuture(Collections.singletonList(relation))); + when(ctx.getRelationService().deleteRelationAsync(any(), eq(relation))).thenReturn(Futures.immediateFuture(true)); + when(ctx.getRelationService().checkRelation(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + .thenReturn(Futures.immediateFuture(false)); + when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) + .thenReturn(Futures.immediateFuture(true)); + + node.onMsg(ctx, msg); + verify(ctx).tellNext(msg, TbRelationTypes.SUCCESS); + } + + public void init(TbCreateRelationNodeConfiguration configuration) throws TbNodeException { + ObjectMapper mapper = new ObjectMapper(); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(configuration)); + + when(ctx.getDbCallbackExecutor()).thenReturn(dbExecutor); + when(ctx.getRelationService()).thenReturn(relationService); + when(ctx.getAssetService()).thenReturn(assetService); + + node = new TbCreateRelationNode(); + node.init(ctx, nodeConfiguration); + } + + private TbCreateRelationNodeConfiguration createRelationNodeConfig() { + TbCreateRelationNodeConfiguration configuration = new TbCreateRelationNodeConfiguration(); + configuration.setDirection(EntitySearchDirection.FROM.name()); + configuration.setRelationType(RELATION_TYPE_CONTAINS); + configuration.setEntityCacheExpiration(300); + configuration.setEntityType("ASSET"); + configuration.setEntityNamePattern("${name}"); + configuration.setEntityTypePattern("${type}"); + configuration.setCreateEntityIfNotExists(false); + configuration.setChangeOriginatorToRelatedEntity(false); + configuration.setRemoveCurrentRelations(false); + return configuration; + } + + private TbCreateRelationNodeConfiguration createRelationNodeConfigWithRemoveCurrentRelations() { + TbCreateRelationNodeConfiguration configuration = createRelationNodeConfig(); + configuration.setRemoveCurrentRelations(true); + return configuration; + } +} From e9ba7655653ddc07a6e09a5dcb26d0ebff0ec1ba Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Fri, 5 Nov 2021 10:36:57 +0200 Subject: [PATCH 217/303] added one more test for create relation node --- .../action/TbCreateRelationNodeTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java index 88172bdaa4..b1e96f228e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.common.util.ListeningExecutor; @@ -33,6 +34,7 @@ import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.relation.EntityRelation; @@ -47,6 +49,7 @@ import org.thingsboard.server.dao.relation.RelationService; import java.util.Collections; import java.util.concurrent.Callable; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @@ -150,6 +153,40 @@ public class TbCreateRelationNodeTest { verify(ctx).tellNext(msg, TbRelationTypes.SUCCESS); } + @Test + public void testCreateNewRelationAndChangeOriginator() throws TbNodeException { + init(createRelationNodeConfigWithChangeOriginator()); + + DeviceId deviceId = new DeviceId(Uuids.timeBased()); + + AssetId assetId = new AssetId(Uuids.timeBased()); + Asset asset = new Asset(); + asset.setId(assetId); + + when(assetService.findAssetByTenantIdAndName(any(), eq("AssetName"))).thenReturn(asset); + when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); + + TbMsgMetaData metaData = new TbMsgMetaData(); + metaData.putValue("name", "AssetName"); + metaData.putValue("type", "AssetType"); + msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getRelationService().checkRelation(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + .thenReturn(Futures.immediateFuture(false)); + when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) + .thenReturn(Futures.immediateFuture(true)); + + node.onMsg(ctx, msg); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); + ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); + verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); + + assertEquals(assetId, originatorCaptor.getValue()); + } + public void init(TbCreateRelationNodeConfiguration configuration) throws TbNodeException { ObjectMapper mapper = new ObjectMapper(); TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(configuration)); @@ -181,4 +218,10 @@ public class TbCreateRelationNodeTest { configuration.setRemoveCurrentRelations(true); return configuration; } + + private TbCreateRelationNodeConfiguration createRelationNodeConfigWithChangeOriginator() { + TbCreateRelationNodeConfiguration configuration = createRelationNodeConfig(); + configuration.setChangeOriginatorToRelatedEntity(true); + return configuration; + } } From f747c8280cbe726a38a158d304ffba8d7f2a5ce9 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Fri, 5 Nov 2021 16:14:53 +0200 Subject: [PATCH 218/303] Fix and refactor bulk importing --- .../service/asset/AssetBulkImportService.java | 73 +++++------- .../device/DeviceBulkImportService.java | 109 ++++++++---------- .../service/edge/EdgeBulkImportService.java | 81 ++++++------- .../importing/AbstractBulkImportService.java | 67 ++++++++--- .../service/security/permission/Resource.java | 2 +- 5 files changed, 166 insertions(+), 166 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java index 2f94ac3b0d..f67b0617ca 100644 --- a/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java @@ -17,78 +17,69 @@ package org.thingsboard.server.service.asset; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.action.EntityActionService; import org.thingsboard.server.service.importing.AbstractBulkImportService; import org.thingsboard.server.service.importing.BulkImportColumnType; -import org.thingsboard.server.service.importing.BulkImportRequest; -import org.thingsboard.server.service.importing.ImportedEntityInfo; -import org.thingsboard.server.service.security.AccessValidator; import org.thingsboard.server.service.security.model.SecurityUser; -import org.thingsboard.server.service.security.permission.AccessControlService; -import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import java.util.Map; import java.util.Optional; @Service @TbCoreComponent +@RequiredArgsConstructor public class AssetBulkImportService extends AbstractBulkImportService { private final AssetService assetService; - public AssetBulkImportService(TelemetrySubscriptionService tsSubscriptionService, TbTenantProfileCache tenantProfileCache, - AccessControlService accessControlService, AccessValidator accessValidator, - EntityActionService entityActionService, TbClusterService clusterService, AssetService assetService) { - super(tsSubscriptionService, tenantProfileCache, accessControlService, accessValidator, entityActionService, clusterService); - this.assetService = assetService; - } - @Override - protected ImportedEntityInfo saveEntity(BulkImportRequest importRequest, Map fields, SecurityUser user) { - ImportedEntityInfo importedEntityInfo = new ImportedEntityInfo<>(); - - Asset asset = new Asset(); - asset.setTenantId(user.getTenantId()); - setAssetFields(asset, fields); - - Asset existingAsset = assetService.findAssetByTenantIdAndName(user.getTenantId(), asset.getName()); - if (existingAsset != null && importRequest.getMapping().getUpdate()) { - importedEntityInfo.setOldEntity(new Asset(existingAsset)); - importedEntityInfo.setUpdated(true); - existingAsset.update(asset); - asset = existingAsset; - } - asset = assetService.saveAsset(asset); - - importedEntityInfo.setEntity(asset); - return importedEntityInfo; - } - - private void setAssetFields(Asset asset, Map fields) { - ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(asset.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); + protected void setEntityFields(Asset entity, Map fields) { + ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(entity.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); fields.forEach((columnType, value) -> { switch (columnType) { case NAME: - asset.setName(value); + entity.setName(value); break; case TYPE: - asset.setType(value); + entity.setType(value); break; case LABEL: - asset.setLabel(value); + entity.setLabel(value); break; case DESCRIPTION: additionalInfo.set("description", new TextNode(value)); break; } }); - asset.setAdditionalInfo(additionalInfo); + entity.setAdditionalInfo(additionalInfo); + } + + @Override + protected Asset saveEntity(Asset entity, Map fields) { + return assetService.saveAsset(entity); + } + + @Override + protected Asset findOrCreateEntity(TenantId tenantId, String name) { + return Optional.ofNullable(assetService.findAssetByTenantIdAndName(tenantId, name)) + .orElseGet(Asset::new); + } + + @Override + protected void setOwners(Asset entity, SecurityUser user) { + entity.setTenantId(user.getTenantId()); + entity.setCustomerId(user.getCustomerId()); + } + + @Override + protected EntityType getEntityType() { + return EntityType.ASSET; } } diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java index 6e31fa1d73..353451df3b 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java @@ -18,18 +18,19 @@ package org.thingsboard.server.service.device; import com.fasterxml.jackson.databind.node.BooleanNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; +import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; @@ -45,17 +46,10 @@ import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.action.EntityActionService; import org.thingsboard.server.service.importing.AbstractBulkImportService; import org.thingsboard.server.service.importing.BulkImportColumnType; -import org.thingsboard.server.service.importing.BulkImportRequest; -import org.thingsboard.server.service.importing.ImportedEntityInfo; -import org.thingsboard.server.service.security.AccessValidator; import org.thingsboard.server.service.security.model.SecurityUser; -import org.thingsboard.server.service.security.permission.AccessControlService; -import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import java.util.Collection; import java.util.EnumSet; @@ -68,6 +62,7 @@ import java.util.concurrent.locks.ReentrantLock; @Service @TbCoreComponent +@RequiredArgsConstructor public class DeviceBulkImportService extends AbstractBulkImportService { protected final DeviceService deviceService; protected final DeviceCredentialsService deviceCredentialsService; @@ -75,33 +70,33 @@ public class DeviceBulkImportService extends AbstractBulkImportService { private final Lock findOrCreateDeviceProfileLock = new ReentrantLock(); - public DeviceBulkImportService(TelemetrySubscriptionService tsSubscriptionService, TbTenantProfileCache tenantProfileCache, - AccessControlService accessControlService, AccessValidator accessValidator, - EntityActionService entityActionService, TbClusterService clusterService, - DeviceService deviceService, DeviceCredentialsService deviceCredentialsService, - DeviceProfileService deviceProfileService) { - super(tsSubscriptionService, tenantProfileCache, accessControlService, accessValidator, entityActionService, clusterService); - this.deviceService = deviceService; - this.deviceCredentialsService = deviceCredentialsService; - this.deviceProfileService = deviceProfileService; + @Override + protected void setEntityFields(Device entity, Map fields) { + ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(entity.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); + fields.forEach((columnType, value) -> { + switch (columnType) { + case NAME: + entity.setName(value); + break; + case TYPE: + entity.setType(value); + break; + case LABEL: + entity.setLabel(value); + break; + case DESCRIPTION: + additionalInfo.set("description", new TextNode(value)); + break; + case IS_GATEWAY: + additionalInfo.set("gateway", BooleanNode.valueOf(Boolean.parseBoolean(value))); + break; + } + entity.setAdditionalInfo(additionalInfo); + }); } @Override - protected ImportedEntityInfo saveEntity(BulkImportRequest importRequest, Map fields, SecurityUser user) { - ImportedEntityInfo importedEntityInfo = new ImportedEntityInfo<>(); - - Device device = new Device(); - device.setTenantId(user.getTenantId()); - setDeviceFields(device, fields); - - Device existingDevice = deviceService.findDeviceByTenantIdAndName(user.getTenantId(), device.getName()); - if (existingDevice != null && importRequest.getMapping().getUpdate()) { - importedEntityInfo.setOldEntity(new Device(existingDevice)); - importedEntityInfo.setUpdated(true); - existingDevice.updateDevice(device); - device = existingDevice; - } - + protected Device saveEntity(Device entity, Map fields) { DeviceCredentials deviceCredentials; try { deviceCredentials = createDeviceCredentials(fields); @@ -112,42 +107,27 @@ public class DeviceBulkImportService extends AbstractBulkImportService { DeviceProfile deviceProfile; if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { - deviceProfile = setUpLwM2mDeviceProfile(user.getTenantId(), device); - } else if (StringUtils.isNotEmpty(device.getType())) { - deviceProfile = deviceProfileService.findOrCreateDeviceProfile(user.getTenantId(), device.getType()); + deviceProfile = setUpLwM2mDeviceProfile(entity.getTenantId(), entity); + } else if (StringUtils.isNotEmpty(entity.getType())) { + deviceProfile = deviceProfileService.findOrCreateDeviceProfile(entity.getTenantId(), entity.getType()); } else { - deviceProfile = deviceProfileService.findDefaultDeviceProfile(user.getTenantId()); + deviceProfile = deviceProfileService.findDefaultDeviceProfile(entity.getTenantId()); } - device.setDeviceProfileId(deviceProfile.getId()); + entity.setDeviceProfileId(deviceProfile.getId()); - device = deviceService.saveDeviceWithCredentials(device, deviceCredentials); + return deviceService.saveDeviceWithCredentials(entity, deviceCredentials); + } - importedEntityInfo.setEntity(device); - return importedEntityInfo; + @Override + protected Device findOrCreateEntity(TenantId tenantId, String name) { + return Optional.ofNullable(deviceService.findDeviceByTenantIdAndName(tenantId, name)) + .orElseGet(Device::new); } - private void setDeviceFields(Device device, Map fields) { - ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(device.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); - fields.forEach((columnType, value) -> { - switch (columnType) { - case NAME: - device.setName(value); - break; - case TYPE: - device.setType(value); - break; - case LABEL: - device.setLabel(value); - break; - case DESCRIPTION: - additionalInfo.set("description", new TextNode(value)); - break; - case IS_GATEWAY: - additionalInfo.set("gateway", BooleanNode.valueOf(Boolean.parseBoolean(value))); - break; - } - device.setAdditionalInfo(additionalInfo); - }); + @Override + protected void setOwners(Device entity, SecurityUser user) { + entity.setTenantId(user.getTenantId()); + entity.setCustomerId(user.getCustomerId()); } @SneakyThrows @@ -273,4 +253,9 @@ public class DeviceBulkImportService extends AbstractBulkImportService { } } + @Override + protected EntityType getEntityType() { + return EntityType.DEVICE; + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java index ec6a2a4e55..3f12d8f6e7 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java @@ -17,90 +17,81 @@ package org.thingsboard.server.service.edge; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.edge.EdgeService; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.action.EntityActionService; import org.thingsboard.server.service.importing.AbstractBulkImportService; import org.thingsboard.server.service.importing.BulkImportColumnType; -import org.thingsboard.server.service.importing.BulkImportRequest; -import org.thingsboard.server.service.importing.ImportedEntityInfo; -import org.thingsboard.server.service.security.AccessValidator; import org.thingsboard.server.service.security.model.SecurityUser; -import org.thingsboard.server.service.security.permission.AccessControlService; -import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import java.util.Map; import java.util.Optional; @Service @TbCoreComponent +@RequiredArgsConstructor public class EdgeBulkImportService extends AbstractBulkImportService { private final EdgeService edgeService; - public EdgeBulkImportService(TelemetrySubscriptionService tsSubscriptionService, TbTenantProfileCache tenantProfileCache, - AccessControlService accessControlService, AccessValidator accessValidator, - EntityActionService entityActionService, TbClusterService clusterService, EdgeService edgeService) { - super(tsSubscriptionService, tenantProfileCache, accessControlService, accessValidator, entityActionService, clusterService); - this.edgeService = edgeService; - } - @Override - protected ImportedEntityInfo saveEntity(BulkImportRequest importRequest, Map fields, SecurityUser user) { - ImportedEntityInfo importedEntityInfo = new ImportedEntityInfo<>(); - - Edge edge = new Edge(); - edge.setTenantId(user.getTenantId()); - setEdgeFields(edge, fields); - - Edge existingEdge = edgeService.findEdgeByTenantIdAndName(user.getTenantId(), edge.getName()); - if (existingEdge != null && importRequest.getMapping().getUpdate()) { - importedEntityInfo.setOldEntity(new Edge(existingEdge)); - importedEntityInfo.setUpdated(true); - existingEdge.update(edge); - edge = existingEdge; - } - edge = edgeService.saveEdge(edge, true); - - importedEntityInfo.setEntity(edge); - return importedEntityInfo; - } - - private void setEdgeFields(Edge edge, Map fields) { - ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(edge.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); + protected void setEntityFields(Edge entity, Map fields) { + ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(entity.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); fields.forEach((columnType, value) -> { switch (columnType) { case NAME: - edge.setName(value); + entity.setName(value); break; case TYPE: - edge.setType(value); + entity.setType(value); break; case LABEL: - edge.setLabel(value); + entity.setLabel(value); break; case DESCRIPTION: additionalInfo.set("description", new TextNode(value)); break; case EDGE_LICENSE_KEY: - edge.setEdgeLicenseKey(value); + entity.setEdgeLicenseKey(value); break; case CLOUD_ENDPOINT: - edge.setCloudEndpoint(value); + entity.setCloudEndpoint(value); break; case ROUTING_KEY: - edge.setRoutingKey(value); + entity.setRoutingKey(value); break; case SECRET: - edge.setSecret(value); + entity.setSecret(value); break; } }); - edge.setAdditionalInfo(additionalInfo); + entity.setAdditionalInfo(additionalInfo); + } + + @Override + protected Edge saveEntity(Edge entity, Map fields) { + return edgeService.saveEdge(entity, true); + } + + @Override + protected Edge findOrCreateEntity(TenantId tenantId, String name) { + return Optional.ofNullable(edgeService.findEdgeByTenantIdAndName(tenantId, name)) + .orElseGet(Edge::new); + } + + @Override + protected void setOwners(Edge entity, SecurityUser user) { + entity.setTenantId(user.getTenantId()); + entity.setCustomerId(user.getCustomerId()); + } + + @Override + protected EntityType getEntityType() { + return EntityType.EDGE; } } diff --git a/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java index bbd18a1f73..d1eef6ec17 100644 --- a/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java @@ -19,19 +19,21 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import lombok.Data; -import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.common.util.ThingsBoardThreadFactory; -import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; @@ -47,6 +49,7 @@ import org.thingsboard.server.service.security.AccessValidator; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.AccessControlService; import org.thingsboard.server.service.security.permission.Operation; +import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import org.thingsboard.server.utils.CsvUtils; import org.thingsboard.server.utils.TypeCastUtil; @@ -68,14 +71,17 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; -@RequiredArgsConstructor -public abstract class AbstractBulkImportService> { - protected final TelemetrySubscriptionService tsSubscriptionService; - protected final TbTenantProfileCache tenantProfileCache; - protected final AccessControlService accessControlService; - protected final AccessValidator accessValidator; - protected final EntityActionService entityActionService; - protected final TbClusterService clusterService; +public abstract class AbstractBulkImportService & HasTenantId> { + @Autowired + private TelemetrySubscriptionService tsSubscriptionService; + @Autowired + private TbTenantProfileCache tenantProfileCache; + @Autowired + private AccessControlService accessControlService; + @Autowired + private AccessValidator accessValidator; + @Autowired + private EntityActionService entityActionService; private static ThreadPoolExecutor executor; @@ -100,7 +106,7 @@ public abstract class AbstractBulkImportService DonAsynchron.submit(() -> { SecurityContextHolder.setContext(securityContext); - ImportedEntityInfo importedEntityInfo = saveEntity(request, entityData.getFields(), user); + ImportedEntityInfo importedEntityInfo = saveEntity(entityData.getFields(), user); E entity = importedEntityInfo.getEntity(); onEntityImported.accept(importedEntityInfo); @@ -127,12 +133,39 @@ public abstract class AbstractBulkImportService saveEntity(BulkImportRequest importRequest, Map fields, SecurityUser user); + @SneakyThrows + private ImportedEntityInfo saveEntity(Map fields, SecurityUser user) { + ImportedEntityInfo importedEntityInfo = new ImportedEntityInfo<>(); + + E entity = findOrCreateEntity(user.getTenantId(), fields.get(BulkImportColumnType.NAME)); + if (entity.getId() != null) { + importedEntityInfo.setOldEntity((E) entity.getClass().getConstructor(entity.getClass()).newInstance(entity)); + importedEntityInfo.setUpdated(true); + } else { + setOwners(entity, user); + } + + setEntityFields(entity, fields); + accessControlService.checkPermission(user, Resource.of(getEntityType()), Operation.WRITE, entity.getId(), entity); + + E savedEntity = saveEntity(entity, fields); + + importedEntityInfo.setEntity(savedEntity); + return importedEntityInfo; + } + + + protected abstract E findOrCreateEntity(TenantId tenantId, String name); + + protected abstract void setOwners(E entity, SecurityUser user); + + protected abstract void setEntityFields(E entity, Map fields); + + protected abstract E saveEntity(E entity, Map fields); + + protected abstract EntityType getEntityType(); + - /* - * Attributes' values are firstly added to JsonObject in order to then make some type cast, - * because we get all values as strings from CSV - * */ private void saveKvs(SecurityUser user, E entity, Map data) { Arrays.stream(BulkImportColumnType.values()) .filter(BulkImportColumnType::isKv) diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java b/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java index c2890836b4..e701810a6c 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java @@ -58,7 +58,7 @@ public enum Resource { public static Resource of(EntityType entityType) { for (Resource resource : Resource.values()) { - if (resource.getEntityType().get() == entityType) { + if (resource.getEntityType().orElse(null) == entityType) { return resource; } } From 423c17ab58bdf994ffb2864e6ea00c3198ff9af0 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 5 Nov 2021 17:35:40 +0200 Subject: [PATCH 219/303] Add /v3/ path to ingress controller to handle new swagger resources --- k8s/common/thingsboard.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/k8s/common/thingsboard.yml b/k8s/common/thingsboard.yml index ee360c27b7..73b7133433 100644 --- a/k8s/common/thingsboard.yml +++ b/k8s/common/thingsboard.yml @@ -420,6 +420,10 @@ spec: backend: serviceName: tb-node servicePort: 8080 + - path: /v3/.* + backend: + serviceName: tb-node + servicePort: 8080 - path: /static/rulenode/.* backend: serviceName: tb-node From 25d8f4d3c0ff65e7279b6624e1e23602c7918fb9 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 5 Nov 2021 17:51:10 +0200 Subject: [PATCH 220/303] Added fields length validation --- .../server/common/data/AdminSettings.java | 2 + .../server/common/data/OtaPackageInfo.java | 3 ++ .../server/common/data/TbResourceInfo.java | 2 + .../server/common/data/Tenant.java | 1 + .../server/common/data/edge/Edge.java | 12 ++++++ .../data/oauth2/OAuth2BasicMapperConfig.java | 7 +++ .../OAuth2ClientRegistrationTemplate.java | 14 ++++++ .../data/oauth2/OAuth2CustomMapperConfig.java | 9 +++- .../data/oauth2/OAuth2MapperConfig.java | 4 ++ .../data/plugin/ComponentDescriptor.java | 3 ++ .../common/data/widget/BaseWidgetType.java | 4 ++ .../common/data/widget/WidgetTypeDetails.java | 3 ++ .../admin/oauth2-settings.component.html | 43 +++++++++++++++++++ .../pages/admin/oauth2-settings.component.ts | 30 +++++++------ .../home/pages/edge/edge.component.html | 7 ++- .../modules/home/pages/edge/edge.component.ts | 4 +- .../pages/widget/widget-editor.component.html | 2 +- .../assets/locale/locale.constant-en_US.json | 14 ++++++ 18 files changed, 146 insertions(+), 18 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java index 5467db00e3..041318d43c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.id.AdminSettingsId; import com.fasterxml.jackson.databind.JsonNode; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @ApiModel @@ -29,6 +30,7 @@ public class AdminSettings extends BaseData { private static final long serialVersionUID = -7670322981725511892L; @NoXss + @Length(fieldName = "key") private String key; private transient JsonNode jsonValue; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java index 429c78e560..7b63c0dba0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java @@ -68,10 +68,13 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo implements Has private String title; @ApiModelProperty(position = 5, value = "Resource type.", example = "LWM2M_MODEL", readOnly = true) private ResourceType resourceType; + @NoXss + @Length(fieldName = "resourceKey") @ApiModelProperty(position = 6, value = "Resource key.", example = "19_1.0", readOnly = true) private String resourceKey; @ApiModelProperty(position = 7, value = "Resource search text.", example = "19_1.0:binaryappdatacontainer", readOnly = true) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java index 982f18e05c..3db0dea9d7 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java @@ -37,6 +37,7 @@ public class Tenant extends ContactBased implements HasTenantId { @ApiModelProperty(position = 3, value = "Title of the tenant", example = "Company A") private String title; @NoXss + @Length(fieldName = "region") @ApiModelProperty(position = 5, value = "Geo region of the tenant", example = "North America") private String region; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java index ddb30ffe64..b7bab9baf7 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.validation.Length; +import org.thingsboard.server.common.data.validation.NoXss; @ApiModel @EqualsAndHashCode(callSuper = true) @@ -41,15 +42,26 @@ public class Edge extends SearchTextBasedWithAdditionalInfo implements H private TenantId tenantId; private CustomerId customerId; private RuleChainId rootRuleChainId; + @NoXss @Length(fieldName = "name") private String name; + @NoXss @Length(fieldName = "type") private String type; + @NoXss @Length(fieldName = "label") private String label; + @NoXss + @Length(fieldName = "routingKey") private String routingKey; + @NoXss + @Length(fieldName = "secret") private String secret; + @NoXss + @Length(fieldName = "edgeLicenseKey", max = 30) private String edgeLicenseKey; + @NoXss + @Length(fieldName = "cloudEndpoint") private String cloudEndpoint; public Edge() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2BasicMapperConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2BasicMapperConfig.java index 652929bc96..937d88b1c1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2BasicMapperConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2BasicMapperConfig.java @@ -21,6 +21,7 @@ import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import org.thingsboard.server.common.data.validation.Length; @Builder(toBuilder = true) @EqualsAndHashCode @@ -28,21 +29,27 @@ import lombok.ToString; @ToString @ApiModel public class OAuth2BasicMapperConfig { + @Length(fieldName = "emailAttributeKey", max = 31) @ApiModelProperty(value = "Email attribute key of OAuth2 principal attributes. " + "Must be specified for BASIC mapper type and cannot be specified for GITHUB type") private final String emailAttributeKey; + @Length(fieldName = "firstNameAttributeKey", max = 31) @ApiModelProperty(value = "First name attribute key") private final String firstNameAttributeKey; + @Length(fieldName = "lastNameAttributeKey", max = 31) @ApiModelProperty(value = "Last name attribute key") private final String lastNameAttributeKey; @ApiModelProperty(value = "Tenant naming strategy. For DOMAIN type, domain for tenant name will be taken from the email (substring before '@')", required = true) private final TenantNameStrategyType tenantNameStrategy; + @Length(fieldName = "tenantNamePattern") @ApiModelProperty(value = "Tenant name pattern for CUSTOM naming strategy. " + "OAuth2 attributes in the pattern can be used by enclosing attribute key in '%{' and '}'", example = "%{email}") private final String tenantNamePattern; + @Length(fieldName = "customerNamePattern") @ApiModelProperty(value = "Customer name pattern. When creating a user on the first OAuth2 log in, if specified, " + "customer name will be used to create or find existing customer in the platform and assign customerId to the user") private final String customerNamePattern; + @Length(fieldName = "defaultDashboardName") @ApiModelProperty(value = "Name of the tenant's dashboard to set as default dashboard for newly created user") private final String defaultDashboardName; @ApiModelProperty(value = "Whether default dashboard should be open in full screen") diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java index 56f866eaab..f4baef2abb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java @@ -24,7 +24,9 @@ import lombok.ToString; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationTemplateId; +import org.thingsboard.server.common.data.validation.Length; +import javax.validation.Valid; import java.util.List; @EqualsAndHashCode(callSuper = true) @@ -34,30 +36,42 @@ import java.util.List; @ApiModel public class OAuth2ClientRegistrationTemplate extends SearchTextBasedWithAdditionalInfo implements HasName { + @Length(fieldName = "providerId") @ApiModelProperty(value = "OAuth2 provider identifier (e.g. its name)", required = true) private String providerId; + @Valid @ApiModelProperty(value = "Default config for mapping OAuth2 log in response to platform entities") private OAuth2MapperConfig mapperConfig; + @Length(fieldName = "authorizationUri") @ApiModelProperty(value = "Default authorization URI of the OAuth2 provider") private String authorizationUri; + @Length(fieldName = "accessTokenUri") @ApiModelProperty(value = "Default access token URI of the OAuth2 provider") private String accessTokenUri; @ApiModelProperty(value = "Default OAuth scopes that will be requested from OAuth2 platform") private List scope; + @Length(fieldName = "userInfoUri") @ApiModelProperty(value = "Default user info URI of the OAuth2 provider") private String userInfoUri; + @Length(fieldName = "userNameAttributeName") @ApiModelProperty(value = "Default name of the username attribute in OAuth2 provider log in response") private String userNameAttributeName; + @Length(fieldName = "jwkSetUri") @ApiModelProperty(value = "Default JSON Web Key URI of the OAuth2 provider") private String jwkSetUri; + @Length(fieldName = "clientAuthenticationMethod") @ApiModelProperty(value = "Default client authentication method to use: 'BASIC' or 'POST'") private String clientAuthenticationMethod; + @Length(fieldName = "comment") @ApiModelProperty(value = "Comment for OAuth2 provider") private String comment; + @Length(fieldName = "loginButtonIcon") @ApiModelProperty(value = "Default log in button icon for OAuth2 provider") private String loginButtonIcon; + @Length(fieldName = "loginButtonLabel") @ApiModelProperty(value = "Default OAuth2 provider label") private String loginButtonLabel; + @Length(fieldName = "helpLink") @ApiModelProperty(value = "Help link for OAuth2 provider") private String helpLink; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2CustomMapperConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2CustomMapperConfig.java index 2dac9b4100..e1bab24619 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2CustomMapperConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2CustomMapperConfig.java @@ -15,15 +15,22 @@ */ package org.thingsboard.server.common.data.oauth2; -import lombok.*; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.thingsboard.server.common.data.validation.Length; @Builder(toBuilder = true) @EqualsAndHashCode @Data @ToString(exclude = {"password"}) public class OAuth2CustomMapperConfig { + @Length(fieldName = "url") private final String url; + @Length(fieldName = "username") private final String username; + @Length(fieldName = "password") private final String password; private final boolean sendToken; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java index df0cc45d7b..9790334efb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java @@ -21,6 +21,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import javax.validation.Valid; + @Builder(toBuilder = true) @EqualsAndHashCode @Data @@ -32,8 +34,10 @@ public class OAuth2MapperConfig { private boolean activateUser; @ApiModelProperty(value = "Type of OAuth2 mapper. Depending on this param, different mapper config fields must be specified", required = true) private MapperType type; + @Valid @ApiModelProperty(value = "Mapper config for BASIC and GITHUB mapper types") private OAuth2BasicMapperConfig basic; + @Valid @ApiModelProperty(value = "Mapper config for CUSTOM mapper type") private OAuth2CustomMapperConfig custom; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentDescriptor.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentDescriptor.java index 5c856cf38d..9ee3320069 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentDescriptor.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentDescriptor.java @@ -21,6 +21,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.*; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.ComponentDescriptorId; +import org.thingsboard.server.common.data.validation.Length; /** * @author Andrew Shvayka @@ -35,12 +36,14 @@ public class ComponentDescriptor extends SearchTextBased @Getter @Setter private ComponentType type; @ApiModelProperty(position = 4, value = "Scope of the Rule Node. Always set to 'TENANT', since no rule chains on the 'SYSTEM' level yet.", readOnly = true, allowableValues = "TENANT", example = "TENANT") @Getter @Setter private ComponentScope scope; + @Length(fieldName = "name") @ApiModelProperty(position = 5, value = "Name of the Rule Node. Taken from the @RuleNode annotation.", readOnly = true, example = "Custom Rule Node") @Getter @Setter private String name; @ApiModelProperty(position = 6, value = "Full name of the Java class that implements the Rule Engine Node interface.", readOnly = true, example = "com.mycompany.CustomRuleNode") @Getter @Setter private String clazz; @ApiModelProperty(position = 7, value = "Complex JSON object that represents the Rule Node configuration.", readOnly = true) @Getter @Setter private transient JsonNode configurationDescriptor; + @Length(fieldName = "actions") @ApiModelProperty(position = 8, value = "Rule Node Actions. Deprecated. Always null.", readOnly = true) @Getter @Setter private String actions; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java index 0cc3e63b05..89452ffdbc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @Data @@ -31,12 +32,15 @@ public class BaseWidgetType extends BaseData implements HasTenantI @ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", readOnly = true) private TenantId tenantId; @NoXss + @Length(fieldName = "bundleAlias") @ApiModelProperty(position = 4, value = "Reference to widget bundle", readOnly = true) private String bundleAlias; @NoXss + @Length(fieldName = "alias") @ApiModelProperty(position = 5, value = "Unique alias that is used in dashboards as a reference widget type", readOnly = true) private String alias; @NoXss + @Length(fieldName = "name") @ApiModelProperty(position = 6, value = "Widget name used in search and UI", readOnly = true) private String name; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java index fe7f87c7af..1af83de90d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java @@ -19,15 +19,18 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.WidgetTypeId; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @Data @JsonPropertyOrder({ "alias", "name", "image", "description", "descriptor" }) public class WidgetTypeDetails extends WidgetType { + @NoXss @ApiModelProperty(position = 8, value = "Base64 encoded thumbnail", readOnly = true) private String image; @NoXss + @Length(fieldName = "description") @ApiModelProperty(position = 9, value = "Description of the widget", readOnly = true) private String description; diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html index 30fc1a66d6..7a90f69a8d 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html @@ -79,6 +79,9 @@ {{ 'admin.error-verification-url' | translate }} + + {{ 'admin.domain-name-max-length' | translate }} + @@ -246,6 +249,9 @@ {{ 'admin.oauth2.client-id-required' | translate }} + + {{ 'admin.oauth2.client-id-max-length' | translate }} + @@ -254,6 +260,9 @@ {{ 'admin.oauth2.client-secret-required' | translate }} + + {{ 'admin.oauth2.client-secret-max-length' | translate }} + @@ -426,17 +435,29 @@ *ngIf="registration.get('mapperConfig.basic.emailAttributeKey').hasError('required')"> {{ 'admin.oauth2.email-attribute-key-required' | translate }} + + {{ 'admin.oauth2.email-attribute-key-max-length' | translate }} +
        admin.oauth2.first-name-attribute-key + + {{ 'admin.oauth2.first-name-attribute-key-max-length' | translate }} + admin.oauth2.last-name-attribute-key + + {{ 'admin.oauth2.last-name-attribute-key-max-length' | translate }} +
        @@ -460,18 +481,30 @@ *ngIf="registration.get('mapperConfig.basic.tenantNamePattern').hasError('required')"> {{ 'admin.oauth2.tenant-name-pattern-required' | translate }} + + {{ 'admin.oauth2.tenant-name-pattern-max-length' | translate }} + admin.oauth2.customer-name-pattern + + {{ 'admin.oauth2.customer-name-pattern-max-length' | translate }} +
        admin.oauth2.default-dashboard-name + + {{ 'admin.oauth2.default-dashboard-name-max-length' | translate }} + @@ -493,18 +526,28 @@ *ngIf="registration.get('mapperConfig.custom.url').hasError('pattern')"> {{ 'admin.oauth2.url-pattern' | translate }} + + {{ 'admin.oauth2.url-max-length' | translate }} +
        common.username + + {{ 'admin.oauth2.username-max-length' | translate }} + common.password + + {{ 'admin.oauth2.password-max-length' | translate }} +
        diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts index 61e001e75b..2ab97d1b44 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts @@ -155,13 +155,18 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha tenantNamePattern = {value: null, disabled: true}; } const basicGroup = this.fb.group({ - emailAttributeKey: [mapperConfigBasic?.emailAttributeKey ? mapperConfigBasic.emailAttributeKey : 'email', Validators.required], - firstNameAttributeKey: [mapperConfigBasic?.firstNameAttributeKey ? mapperConfigBasic.firstNameAttributeKey : ''], - lastNameAttributeKey: [mapperConfigBasic?.lastNameAttributeKey ? mapperConfigBasic.lastNameAttributeKey : ''], + emailAttributeKey: [mapperConfigBasic?.emailAttributeKey ? mapperConfigBasic.emailAttributeKey : 'email', + [Validators.required, Validators.maxLength(31)]], + firstNameAttributeKey: [mapperConfigBasic?.firstNameAttributeKey ? mapperConfigBasic.firstNameAttributeKey : '', + Validators.maxLength(31)], + lastNameAttributeKey: [mapperConfigBasic?.lastNameAttributeKey ? mapperConfigBasic.lastNameAttributeKey : '', + Validators.maxLength(31)], tenantNameStrategy: [mapperConfigBasic?.tenantNameStrategy ? mapperConfigBasic.tenantNameStrategy : TenantNameStrategy.DOMAIN], - tenantNamePattern: [tenantNamePattern, Validators.required], - customerNamePattern: [mapperConfigBasic?.customerNamePattern ? mapperConfigBasic.customerNamePattern : null], - defaultDashboardName: [mapperConfigBasic?.defaultDashboardName ? mapperConfigBasic.defaultDashboardName : null], + tenantNamePattern: [tenantNamePattern, [Validators.required, Validators.maxLength(255)]], + customerNamePattern: [mapperConfigBasic?.customerNamePattern ? mapperConfigBasic.customerNamePattern : null, + Validators.maxLength(255)], + defaultDashboardName: [mapperConfigBasic?.defaultDashboardName ? mapperConfigBasic.defaultDashboardName : null, + Validators.maxLength(255)], alwaysFullScreen: [isDefinedAndNotNull(mapperConfigBasic?.alwaysFullScreen) ? mapperConfigBasic.alwaysFullScreen : false] }); @@ -178,9 +183,10 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha private formCustomGroup(mapperConfigCustom?: MapperConfigCustom): FormGroup { return this.fb.group({ - url: [mapperConfigCustom?.url ? mapperConfigCustom.url : null, [Validators.required, Validators.pattern(this.URL_REGEXP)]], - username: [mapperConfigCustom?.username ? mapperConfigCustom.username : null], - password: [mapperConfigCustom?.password ? mapperConfigCustom.password : null] + url: [mapperConfigCustom?.url ? mapperConfigCustom.url : null, + [Validators.required, Validators.pattern(this.URL_REGEXP), Validators.maxLength(255)]], + username: [mapperConfigCustom?.username ? mapperConfigCustom.username : null, Validators.maxLength(255)], + password: [mapperConfigCustom?.password ? mapperConfigCustom.password : null, Validators.maxLength(255)] }); } @@ -266,7 +272,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha private buildDomainInfoForm(domainInfo?: OAuth2DomainInfo): FormGroup { return this.fb.group({ name: [domainInfo ? domainInfo.name : this.window.location.hostname, [ - Validators.required, + Validators.required, Validators.maxLength(255), Validators.pattern(this.DOMAIN_AND_PORT_REGEXP)]], scheme: [domainInfo?.scheme ? domainInfo.scheme : DomainSchema.HTTPS, Validators.required] }, {validators: this.uniqueDomainValidator}); @@ -300,8 +306,8 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha platforms: [registration?.platforms ? registration.platforms : []], loginButtonLabel: [registration?.loginButtonLabel ? registration.loginButtonLabel : null, Validators.required], loginButtonIcon: [registration?.loginButtonIcon ? registration.loginButtonIcon : null], - clientId: [registration?.clientId ? registration.clientId : '', Validators.required], - clientSecret: [registration?.clientSecret ? registration.clientSecret : '', Validators.required], + clientId: [registration?.clientId ? registration.clientId : '', [Validators.required, Validators.maxLength(255)]], + clientSecret: [registration?.clientSecret ? registration.clientSecret : '', [Validators.required, Validators.maxLength(2048)]], accessTokenUri: [registration?.accessTokenUri ? registration.accessTokenUri : '', [Validators.required, Validators.pattern(this.URL_REGEXP)]], diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge.component.html b/ui-ngx/src/app/modules/home/pages/edge/edge.component.html index 6d357ffee8..00f32ed578 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge.component.html +++ b/ui-ngx/src/app/modules/home/pages/edge/edge.component.html @@ -143,8 +143,8 @@ {{ 'edge.edge-license-key-required' | translate }} - - {{ 'edge.type-max-length' | translate }} + + {{ 'edge.edge-license-key-max-length' | translate }}
        @@ -156,6 +156,9 @@ {{ 'edge.cloud-endpoint-required' | translate }} + + {{ 'edge.cloud-endpoint-max-length' | translate }} + diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge.component.ts b/ui-ngx/src/app/modules/home/pages/edge/edge.component.ts index 397423b863..162bfeb463 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge.component.ts +++ b/ui-ngx/src/app/modules/home/pages/edge/edge.component.ts @@ -73,8 +73,8 @@ export class EdgeComponent extends EntityComponent { name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], type: [entity?.type ? entity.type : 'default', [Validators.required, Validators.maxLength(255)]], label: [entity ? entity.label : '', Validators.maxLength(255)], - cloudEndpoint: [null, [Validators.required]], - edgeLicenseKey: ['', [Validators.required]], + cloudEndpoint: [null, [Validators.required, Validators.maxLength(255)]], + edgeLicenseKey: ['', [Validators.required, Validators.maxLength(30)]], routingKey: this.fb.control({value: entity ? entity.routingKey : null, disabled: true}), secret: this.fb.control({value: entity ? entity.secret : null, disabled: true}), additionalInfo: this.fb.group( diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html index 399c85b401..f935087bdf 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html @@ -21,7 +21,7 @@ - diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index ae80aeb230..8b7ff34a54 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -158,6 +158,7 @@ "user-lockout-notification-email": "In case user account lockout, send notification to email", "domain-name": "Domain name", "domain-name-unique": "Domain name and protocol need to unique.", + "domain-name-max-length": "Domain name should be less than 256", "error-verification-url": "A domain name shouldn't contain symbols '/' and ':'. Example: thingsboard.io", "oauth2": { "access-token-uri": "Access token URI", @@ -174,21 +175,28 @@ "client-authentication-method": "Client authentication method", "client-id": "Client ID", "client-id-required": "Client ID is required.", + "client-id-max-length": "Client ID should be less than 256", "client-secret": "Client secret", "client-secret-required": "Client secret is required.", + "client-secret-max-length": "Client secret should be less than 2049", "custom-setting": "Custom settings", "customer-name-pattern": "Customer name pattern", + "customer-name-pattern-max-length": "Customer name pattern should be less than 256", "default-dashboard-name": "Default dashboard name", + "default-dashboard-name-max-length": "Default dashboard name should be less than 256", "delete-domain-text": "Be careful, after the confirmation a domain and all provider data will be unavailable.", "delete-domain-title": "Are you sure you want to delete settings the domain '{{domainName}}'?", "delete-registration-text": "Be careful, after the confirmation a provider data will be unavailable.", "delete-registration-title": "Are you sure you want to delete the provider '{{name}}'?", "email-attribute-key": "Email attribute key", "email-attribute-key-required": "Email attribute key is required.", + "email-attribute-key-max-length": "Email attribute key should be less than 32", "first-name-attribute-key": "First name attribute key", + "first-name-attribute-key-max-length": "First name attribute key should be less than 32", "general": "General", "jwk-set-uri": "JSON Web Key URI", "last-name-attribute-key": "Last name attribute key", + "last-name-attribute-key-max-length": "Last name attribute key should be less than 32", "login-button-icon": "Login button icon", "login-button-label": "Provider label", "login-button-label-placeholder": "Login with $(Provider label)", @@ -197,6 +205,7 @@ "mapper": "Mapper", "new-domain": "New domain", "oauth2": "OAuth2", + "password-max-length": "Password should be less than 256", "redirect-uri-template": "Redirect URI template", "copy-redirect-uri": "Copy redirect URI", "registration-id": "Registration ID", @@ -206,14 +215,17 @@ "scope-required": "Scope is required.", "tenant-name-pattern": "Tenant name pattern", "tenant-name-pattern-required": "Tenant name pattern is required.", + "tenant-name-pattern-max-length": "Tenant name pattern ishould be less than 256", "tenant-name-strategy": "Tenant name strategy", "type": "Mapper type", "uri-pattern-error": "Invalid URI format.", "url": "URL", "url-pattern": "Invalid URL format.", "url-required": "URL is required.", + "url-max-length": "URL should be less than 256", "user-info-uri": "User info URI", "user-info-uri-required": "User info URI is required.", + "username-max-length": "User name should be less than 256", "user-name-attribute-name": "User name attribute key", "user-name-attribute-name-required": "User name attribute key is required", "protocol": "Protocol", @@ -1448,9 +1460,11 @@ "name-required": "Name is required.", "edge-license-key": "Edge License Key", "edge-license-key-required": "Edge License Key is required.", + "edge-license-key-max-length": "Edge License Key should be less than 31", "edge-license-key-hint": "To obtain your license please navigate to the pricing page and select the best license option for your case.", "cloud-endpoint": "Cloud Endpoint", "cloud-endpoint-required": "Cloud Endpoint is required.", + "cloud-endpoint-max-length": "Cloud Endpoint should be less than 256", "cloud-endpoint-hint": "Edge requires HTTP(s) access to Cloud (ThingsBoard CE/PE) to verify the license key. Please specify Cloud URL that Edge is able to connect to.", "description": "Description", "details": "Details", From 676a60e8042ce105427d7475f1c09fa3f55aede8 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Fri, 5 Nov 2021 18:26:53 +0200 Subject: [PATCH 221/303] Revert "[3.3.3] Entities search within all tenants" --- .../controller/EntityQueryController.java | 83 +------ .../data/search/EntitiesSearchRequest.java | 25 --- .../data/search/EntitySearchResult.java | 50 ----- .../service/query/EntitiesSearchService.java | 26 --- .../query/EntitiesSearchServiceImpl.java | 208 ------------------ .../permission/PermissionChecker.java | 1 - .../permission/SysAdminPermissions.java | 31 ++- .../common/data/query/EntityFilterType.java | 3 +- .../data/query/EntityNameOrIdFilter.java | 32 --- .../query/DefaultEntityQueryRepository.java | 52 +---- .../dao/sql/query/EntityKeyMapping.java | 60 +---- 11 files changed, 39 insertions(+), 532 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java delete mode 100644 application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index e5467c8ae9..019066c636 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -17,10 +17,9 @@ package org.thingsboard.server.controller; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; -import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -37,30 +36,20 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; -import org.thingsboard.server.data.search.EntitiesSearchRequest; -import org.thingsboard.server.data.search.EntitySearchResult; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.query.EntitiesSearchService; import org.thingsboard.server.service.query.EntityQueryService; import static org.thingsboard.server.controller.ControllerConstants.ALARM_DATA_QUERY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_COUNT_QUERY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_DATA_QUERY_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; -import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; -import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; @RestController @TbCoreComponent @RequestMapping("/api") -@RequiredArgsConstructor public class EntityQueryController extends BaseController { - private final EntityQueryService entityQueryService; - private final EntitiesSearchService entitiesSearchService; + @Autowired + private EntityQueryService entityQueryService; private static final int MAX_PAGE_SIZE = 100; @@ -134,70 +123,4 @@ public class EntityQueryController extends BaseController { } } - @ApiOperation(value = "Search entities (searchEntities)", notes = "Search entities with specified entity type by id or name within the whole platform. " + - "Searchable entity types are: CUSTOMER, USER, DEVICE, DEVICE_PROFILE, ASSET, ENTITY_VIEW, DASHBOARD, " + - "RULE_CHAIN, EDGE, OTA_PACKAGE, TB_RESOURCE, WIDGETS_BUNDLE, TENANT, TENANT_PROFILE." + NEW_LINE + - "The platform will search for entities, where a name contains the search text (case-insensitively), " + - "or if the search query is a valid UUID (e.g. 128e4d40-26b3-11ec-aaeb-c7661c54701e) then " + - "it will also search for an entity where id fully matches the query. If search query is empty " + - "then all entities will be returned (according to page number, page size and sorting)." + NEW_LINE + - "The returned result is a page of EntitySearchResult, which contains: " + - "entity id, entity fields represented as strings, tenant info and owner info. " + - "Returned entity fields are: name, type (will be present for USER, DEVICE, ASSET, ENTITY_VIEW, RULE_CHAIN, " + - "EDGE, OTA_PACKAGE, TB_RESOURCE entity types; in case of USER - the type is its authority), " + - "createdTime and lastActivityTime (will only be present for DEVICE and USER; for USER it is its last login time). " + - "Tenant info contains tenant's id and title; owner info contains the same info for an entity's owner " + - "(its customer, or if it is not a customer's entity - tenant)." + NEW_LINE + - "Example response value:\n" + - "{\n" + - " \"data\": [\n" + - " {\n" + - " \"entityId\": {\n" + - " \"entityType\": \"DEVICE\",\n" + - " \"id\": \"48be0670-25c9-11ec-a618-8165eb6b112a\"\n" + - " },\n" + - " \"fields\": {\n" + - " \"name\": \"Thermostat T1\",\n" + - " \"createdTime\": \"1633430698071\",\n" + - " \"lastActivityTime\": \"1635761085285\",\n" + - " \"type\": \"thermostat\"\n" + - " },\n" + - " \"tenantInfo\": {\n" + - " \"id\": {\n" + - " \"entityType\": \"TENANT\",\n" + - " \"id\": \"2ddd6120-25c9-11ec-a618-8165eb6b112a\"\n" + - " },\n" + - " \"name\": \"Tenant\"\n" + - " },\n" + - " \"ownerInfo\": {\n" + - " \"id\": {\n" + - " \"entityType\": \"CUSTOMER\",\n" + - " \"id\": \"26cba800-eee3-11eb-9e2c-fb031bd4619c\"\n" + - " },\n" + - " \"name\": \"Customer A\"\n" + - " }\n" + - " }\n" + - " ],\n" + - " \"totalPages\": 1,\n" + - " \"totalElements\": 1,\n" + - " \"hasNext\": false\n" + - "}") - @PostMapping("/entities/search") - @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") - public PageData searchEntities(@RequestBody EntitiesSearchRequest request, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) - @RequestParam int page, - @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) - @RequestParam int pageSize, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "name, type, createdTime, lastActivityTime, createdTime, tenantId, customerId", required = false) - @RequestParam(required = false) String sortProperty, - @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES, required = false) - @RequestParam(required = false) String sortOrder) throws ThingsboardException { - try { - return entitiesSearchService.searchEntities(getCurrentUser(), request, createPageLink(pageSize, page, null, sortProperty, sortOrder)); - } catch (Exception e) { - throw handleException(e); - } - } - } diff --git a/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java b/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java deleted file mode 100644 index 48f8966107..0000000000 --- a/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright © 2016-2021 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.data.search; - -import lombok.Data; -import org.thingsboard.server.common.data.EntityType; - -@Data -public class EntitiesSearchRequest { - private EntityType entityType; - private String searchQuery; -} diff --git a/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java b/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java deleted file mode 100644 index a26d580b7d..0000000000 --- a/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright © 2016-2021 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.data.search; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; - -import java.util.Map; - -@Data -public class EntitySearchResult { - private EntityId entityId; - private Map fields; - - private EntityTenantInfo tenantInfo; - private EntityOwnerInfo ownerInfo; - - @Data - @AllArgsConstructor - @NoArgsConstructor - public static final class EntityTenantInfo { - private TenantId id; - private String name; - } - - @Data - @AllArgsConstructor - @NoArgsConstructor - public static final class EntityOwnerInfo { - private EntityId id; - private String name; - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java b/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java deleted file mode 100644 index 36a34f89e7..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright © 2016-2021 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.query; - -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.data.search.EntitiesSearchRequest; -import org.thingsboard.server.data.search.EntitySearchResult; -import org.thingsboard.server.service.security.model.SecurityUser; - -public interface EntitiesSearchService { - PageData searchEntities(SecurityUser user, EntitiesSearchRequest request, PageLink pageLink); -} diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java deleted file mode 100644 index 1753a49c0d..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright © 2016-2021 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.query; - -import com.google.common.base.Strings; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.ContactBased; -import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.SortOrder; -import org.thingsboard.server.common.data.query.EntityData; -import org.thingsboard.server.common.data.query.EntityDataPageLink; -import org.thingsboard.server.common.data.query.EntityDataQuery; -import org.thingsboard.server.common.data.query.EntityDataSortOrder; -import org.thingsboard.server.common.data.query.EntityKey; -import org.thingsboard.server.common.data.query.EntityKeyType; -import org.thingsboard.server.common.data.query.EntityNameOrIdFilter; -import org.thingsboard.server.dao.customer.CustomerService; -import org.thingsboard.server.dao.tenant.TenantService; -import org.thingsboard.server.data.search.EntitiesSearchRequest; -import org.thingsboard.server.data.search.EntitySearchResult; -import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.security.model.SecurityUser; -import org.thingsboard.server.service.state.DefaultDeviceStateService; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.thingsboard.server.common.data.EntityType.ASSET; -import static org.thingsboard.server.common.data.EntityType.CUSTOMER; -import static org.thingsboard.server.common.data.EntityType.DASHBOARD; -import static org.thingsboard.server.common.data.EntityType.DEVICE; -import static org.thingsboard.server.common.data.EntityType.DEVICE_PROFILE; -import static org.thingsboard.server.common.data.EntityType.EDGE; -import static org.thingsboard.server.common.data.EntityType.ENTITY_VIEW; -import static org.thingsboard.server.common.data.EntityType.OTA_PACKAGE; -import static org.thingsboard.server.common.data.EntityType.RULE_CHAIN; -import static org.thingsboard.server.common.data.EntityType.TB_RESOURCE; -import static org.thingsboard.server.common.data.EntityType.TENANT; -import static org.thingsboard.server.common.data.EntityType.TENANT_PROFILE; -import static org.thingsboard.server.common.data.EntityType.USER; -import static org.thingsboard.server.common.data.EntityType.WIDGETS_BUNDLE; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.CREATED_TIME; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.CUSTOMER_ID; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.LAST_ACTIVITY_TIME; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.NAME; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.TENANT_ID; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.TYPE; - -@Service -@TbCoreComponent -@RequiredArgsConstructor -@Slf4j -public class EntitiesSearchServiceImpl implements EntitiesSearchService { - private final EntityQueryService entityQueryService; - - private final TenantService tenantService; - private final CustomerService customerService; - private final DefaultDeviceStateService deviceStateService; - - private static final List entityResponseFields = Stream.of(CREATED_TIME, NAME, TYPE, TENANT_ID, CUSTOMER_ID) - .map(field -> new EntityKey(EntityKeyType.ENTITY_FIELD, field)) - .collect(Collectors.toList()); - - private static final Set searchableEntityTypes = EnumSet.of( - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, RULE_CHAIN, ENTITY_VIEW, - WIDGETS_BUNDLE, TENANT_PROFILE, DEVICE_PROFILE, TB_RESOURCE, OTA_PACKAGE, EDGE - ); - - @Override - public PageData searchEntities(SecurityUser user, EntitiesSearchRequest request, PageLink pageLink) { - EntityType entityType = request.getEntityType(); - if (!searchableEntityTypes.contains(entityType)) { - return new PageData<>(); - } - - EntityDataQuery query = createSearchQuery(request.getSearchQuery(), entityType, pageLink); - PageData resultPage = entityQueryService.findEntityDataByQuery(user, query); - - Map> localOwnersCache = new HashMap<>(); - return resultPage.mapData(entityData -> { - Map fields = new HashMap<>(); - entityData.getLatest().values().stream() - .flatMap(values -> values.entrySet().stream()) - .forEach(entry -> fields.put(entry.getKey(), Strings.emptyToNull(entry.getValue().getValue()))); - - EntitySearchResult entitySearchResult = new EntitySearchResult(); - - entitySearchResult.setEntityId(entityData.getEntityId()); - entitySearchResult.setFields(fields); - setOwnerInfo(entitySearchResult, localOwnersCache); - - return entitySearchResult; - }); - } - - private EntityDataQuery createSearchQuery(String searchQuery, EntityType entityType, PageLink pageLink) { - EntityDataPageLink entityDataPageLink = new EntityDataPageLink(); - entityDataPageLink.setPageSize(pageLink.getPageSize()); - entityDataPageLink.setPage(pageLink.getPage()); - if (pageLink.getSortOrder() != null && StringUtils.isNotEmpty(pageLink.getSortOrder().getProperty())) { - entityDataPageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, pageLink.getSortOrder().getProperty()), - EntityDataSortOrder.Direction.valueOf(Optional.ofNullable(pageLink.getSortOrder().getDirection()).orElse(SortOrder.Direction.ASC).name()))); - } - - EntityNameOrIdFilter filter = new EntityNameOrIdFilter(); - filter.setEntityType(entityType); - filter.setNameOrId(searchQuery); - - List entityFields = entityResponseFields; - List latestValues = Collections.emptyList(); - - if (entityType == USER) { - entityFields = new ArrayList<>(entityFields); - entityFields.add(new EntityKey(EntityKeyType.ENTITY_FIELD, LAST_ACTIVITY_TIME)); - } else if (entityType == DEVICE) { - EntityKey lastActivityTimeKey; - if (deviceStateService.isPersistToTelemetry()) { - lastActivityTimeKey = new EntityKey(EntityKeyType.TIME_SERIES, LAST_ACTIVITY_TIME); - } else { - lastActivityTimeKey = new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, LAST_ACTIVITY_TIME); - } - latestValues = List.of(lastActivityTimeKey); - if (entityDataPageLink.getSortOrder() != null && entityDataPageLink.getSortOrder().getKey().getKey().equals(LAST_ACTIVITY_TIME)) { - entityDataPageLink.getSortOrder().setKey(lastActivityTimeKey); - } - } - - return new EntityDataQuery(filter, entityDataPageLink, entityFields, latestValues, Collections.emptyList()); - } - - private void setOwnerInfo(EntitySearchResult entitySearchResult, Map> localOwnersCache) { - Map fields = entitySearchResult.getFields(); - - UUID tenantUuid = toUuid(fields.remove(TENANT_ID)); - UUID customerUuid = toUuid(fields.remove(CUSTOMER_ID)); - - Tenant tenant = null; - if (tenantUuid != null) { - tenant = getTenant(new TenantId(tenantUuid), localOwnersCache); - } - - ContactBased owner; - if (customerUuid != null) { - owner = getCustomer(new CustomerId(customerUuid), localOwnersCache); - } else { - owner = tenant; - } - - if (tenant != null) { - entitySearchResult.setTenantInfo(new EntitySearchResult.EntityTenantInfo(tenant.getId(), tenant.getName())); - } - if (owner != null) { - entitySearchResult.setOwnerInfo(new EntitySearchResult.EntityOwnerInfo(owner.getId(), owner.getName())); - } - } - - private Tenant getTenant(TenantId tenantId, Map> localOwnersCache) { - return (Tenant) localOwnersCache.computeIfAbsent(tenantId, id -> tenantService.findTenantById(tenantId)); - } - - private Customer getCustomer(CustomerId customerId, Map> localOwnersCache) { - return (Customer) localOwnersCache.computeIfAbsent(customerId, id -> customerService.findCustomerById(TenantId.SYS_TENANT_ID, customerId)); - } - - private UUID toUuid(String uuid) { - try { - UUID id = UUID.fromString(uuid); - if (!id.equals(EntityId.NULL_UUID)) { - return id; - } - } catch (Exception ignored) {} - - return null; - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java b/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java index 45a43876e6..3f6e16d753 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java @@ -69,6 +69,5 @@ public interface PermissionChecker { } }; - PermissionChecker allowReadPermissionChecker = new GenericPermissionChecker(Operation.READ, Operation.READ_TELEMETRY, Operation.READ_ATTRIBUTES); } diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java index 8f9648dc93..f703102e18 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java @@ -17,7 +17,10 @@ package org.thingsboard.server.service.security.permission; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.service.security.model.SecurityUser; @Component(value="sysAdminPermissions") @@ -26,29 +29,23 @@ public class SysAdminPermissions extends AbstractPermissions { public SysAdminPermissions() { super(); put(Resource.ADMIN_SETTINGS, PermissionChecker.allowAllPermissionChecker); - put(Resource.DASHBOARD, PermissionChecker.allowReadPermissionChecker); + put(Resource.DASHBOARD, new PermissionChecker.GenericPermissionChecker(Operation.READ)); put(Resource.TENANT, PermissionChecker.allowAllPermissionChecker); - put(Resource.RULE_CHAIN, PermissionChecker.allowReadPermissionChecker); - put(Resource.USER, PermissionChecker.allowAllPermissionChecker); + put(Resource.RULE_CHAIN, systemEntityPermissionChecker); + put(Resource.USER, userPermissionChecker); put(Resource.WIDGETS_BUNDLE, systemEntityPermissionChecker); put(Resource.WIDGET_TYPE, systemEntityPermissionChecker); put(Resource.OAUTH2_CONFIGURATION_INFO, PermissionChecker.allowAllPermissionChecker); put(Resource.OAUTH2_CONFIGURATION_TEMPLATE, PermissionChecker.allowAllPermissionChecker); put(Resource.TENANT_PROFILE, PermissionChecker.allowAllPermissionChecker); - put(Resource.TB_RESOURCE, PermissionChecker.allowAllPermissionChecker); - put(Resource.CUSTOMER, PermissionChecker.allowReadPermissionChecker); - put(Resource.ASSET, PermissionChecker.allowReadPermissionChecker); - put(Resource.DEVICE, PermissionChecker.allowReadPermissionChecker); - put(Resource.ENTITY_VIEW, PermissionChecker.allowReadPermissionChecker); - put(Resource.DEVICE_PROFILE, PermissionChecker.allowReadPermissionChecker); - put(Resource.OTA_PACKAGE, PermissionChecker.allowReadPermissionChecker); - put(Resource.EDGE, PermissionChecker.allowReadPermissionChecker); + put(Resource.TB_RESOURCE, systemEntityPermissionChecker); } private static final PermissionChecker systemEntityPermissionChecker = new PermissionChecker() { @Override public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { + if (entity.getTenantId() != null && !entity.getTenantId().isNullUid()) { return false; } @@ -56,4 +53,16 @@ public class SysAdminPermissions extends AbstractPermissions { } }; + private static final PermissionChecker userPermissionChecker = new PermissionChecker() { + + @Override + public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) { + if (Authority.CUSTOMER_USER.equals(userEntity.getAuthority())) { + return false; + } + return true; + } + + }; + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java index c75d6bf4df..1a843c7b0f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java @@ -29,8 +29,7 @@ public enum EntityFilterType { DEVICE_SEARCH_QUERY("deviceSearchQuery"), ENTITY_VIEW_SEARCH_QUERY("entityViewSearchQuery"), EDGE_SEARCH_QUERY("edgeSearchQuery"), - API_USAGE_STATE("apiUsageState"), - ENTITY_NAME_OR_ID("entityNameOrId"); + API_USAGE_STATE("apiUsageState"); private final String label; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java deleted file mode 100644 index 1fcb9e9350..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.common.data.query; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.thingsboard.server.common.data.EntityType; - -@EqualsAndHashCode(callSuper = true) -@Data -public class EntityNameOrIdFilter extends EntitySearchQueryFilter { - private String nameOrId; - private EntityType entityType; - - @Override - public EntityFilterType getType() { - return EntityFilterType.ENTITY_NAME_OR_ID; - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index cbecc96f59..4b331f78f2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -44,7 +44,6 @@ import org.thingsboard.server.common.data.query.EntityFilterType; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.EntityListFilter; import org.thingsboard.server.common.data.query.EntityNameFilter; -import org.thingsboard.server.common.data.query.EntityNameOrIdFilter; import org.thingsboard.server.common.data.query.EntitySearchQueryFilter; import org.thingsboard.server.common.data.query.EntityTypeFilter; import org.thingsboard.server.common.data.query.EntityViewSearchQueryFilter; @@ -237,12 +236,6 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { entityTableMap.put(EntityType.TENANT, "tenant"); entityTableMap.put(EntityType.API_USAGE_STATE, SELECT_API_USAGE_STATE); entityTableMap.put(EntityType.EDGE, "edge"); - entityTableMap.put(EntityType.RULE_CHAIN, "rule_chain"); - entityTableMap.put(EntityType.WIDGETS_BUNDLE, "widgets_bundle"); - entityTableMap.put(EntityType.TENANT_PROFILE, "tenant_profile"); - entityTableMap.put(EntityType.DEVICE_PROFILE, "device_profile"); - entityTableMap.put(EntityType.TB_RESOURCE, "resource"); - entityTableMap.put(EntityType.OTA_PACKAGE, "ota_package"); } public static EntityType[] RELATION_QUERY_ENTITY_TYPES = new EntityType[]{ @@ -448,7 +441,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { Optional sortOrderMappingOpt = mappings.stream().filter(EntityKeyMapping::isSortOrder).findFirst(); if (sortOrderMappingOpt.isPresent()) { EntityKeyMapping sortOrderMapping = sortOrderMappingOpt.get(); - String direction = sortOrder.getDirection() == EntityDataSortOrder.Direction.ASC ? "asc" : "desc nulls last"; + String direction = sortOrder.getDirection() == EntityDataSortOrder.Direction.ASC ? "asc" : "desc"; if (sortOrderMapping.getEntityKey().getType() == EntityKeyType.ENTITY_FIELD) { dataQuery = String.format("%s order by %s %s, result.id %s", dataQuery, sortOrderMapping.getValueAlias(), direction, direction); } else { @@ -478,26 +471,15 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType()); String result = permissionQuery; if (!entityFilterQuery.isEmpty()) { - if (!result.isEmpty()) { - result += " and (" + entityFilterQuery + ")"; - } else { - result = "(" + entityFilterQuery + ")"; - } + result += " and (" + entityFilterQuery + ")"; } if (!entityFieldsQuery.isEmpty()) { - if (!result.isEmpty()) { - result += " and (" + entityFieldsQuery + ")"; - } else { - result = "(" + entityFieldsQuery + ")"; - } + result += " and (" + entityFieldsQuery + ")"; } return result; } private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter) { - if (ctx.getTenantId().equals(TenantId.SYS_TENANT_ID)) { - return ""; - } switch (entityFilter.getType()) { case RELATIONS_QUERY: case DEVICE_SEARCH_QUERY: @@ -566,8 +548,6 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { case API_USAGE_STATE: case ENTITY_TYPE: return ""; - case ENTITY_NAME_OR_ID: - return entityNameOrIdQuery(ctx, (EntityNameOrIdFilter) entityFilter); default: throw new RuntimeException("Not implemented!"); } @@ -779,27 +759,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private String entityNameQuery(QueryContext ctx, EntityNameFilter filter) { ctx.addStringParameter("entity_filter_name_filter", filter.getEntityNameFilter()); - return "lower(e.search_text) like lower(concat('%', :entity_filter_name_filter, '%'))"; - } - - private String entityNameOrIdQuery(QueryContext ctx, EntityNameOrIdFilter filter) { - String nameOrId = filter.getNameOrId(); - if (StringUtils.isNotEmpty(nameOrId)) { - nameOrId = nameOrId.replaceAll("%", "\\\\%").replaceAll("_", "\\\\_"); - ctx.addStringParameter("entity_id_or_search_text_filter", nameOrId); - String query = ""; - - String searchTextField = EntityKeyMapping.searchTextFields.get(filter.getEntityType()); - query += "lower(e." + searchTextField + ") like lower(concat('%', :entity_id_or_search_text_filter, '%'))"; - - try { - UUID.fromString(nameOrId); - query += " or e.id = :entity_id_or_search_text_filter::uuid"; - } catch (Exception ignored) {} - - return query; - } - return "true"; + return "lower(e.search_text) like lower(concat(:entity_filter_name_filter, '%%'))"; } private String typeQuery(QueryContext ctx, EntityFilter filter) { @@ -827,7 +787,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { } ctx.addStringParameter("entity_filter_type_query_type", type); ctx.addStringParameter("entity_filter_type_query_name", name); - return "e.type = :entity_filter_type_query_type and lower(e.search_text) like lower(concat('%', :entity_filter_type_query_name, '%'))"; + return "e.type = :entity_filter_type_query_type and lower(e.search_text) like lower(concat(:entity_filter_type_query_name, '%%'))"; } private EntityType resolveEntityType(EntityFilter entityFilter) { @@ -856,8 +816,6 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { return ((RelationsQueryFilter) entityFilter).getRootEntity().getEntityType(); case API_USAGE_STATE: return EntityType.API_USAGE_STATE; - case ENTITY_NAME_OR_ID: - return ((EntityNameOrIdFilter) entityFilter).getEntityType(); default: throw new RuntimeException("Not implemented!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 3d40156329..caed48758a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -38,7 +38,6 @@ import org.thingsboard.server.dao.model.ModelConstants; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -54,8 +53,6 @@ public class EntityKeyMapping { private static final Map> allowedEntityFieldMap = new HashMap<>(); private static final Map entityFieldColumnMap = new HashMap<>(); private static final Map> aliases = new HashMap<>(); - private static final Map> propertiesFunctions = new EnumMap<>(EntityType.class); - public static final Map searchTextFields = new EnumMap<>(EntityType.class); public static final String CREATED_TIME = "createdTime"; public static final String ENTITY_TYPE = "entityType"; @@ -75,51 +72,35 @@ public class EntityKeyMapping { public static final String ZIP = "zip"; public static final String PHONE = "phone"; public static final String ADDITIONAL_INFO = "additionalInfo"; - public static final String TENANT_ID = "tenantId"; - public static final String CUSTOMER_ID = "customerId"; - public static final String AUTHORITY = "authority"; - public static final String RESOURCE_TYPE = "resourceType"; - public static final String LAST_ACTIVITY_TIME = "lastActivityTime"; - public static final List typedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, ADDITIONAL_INFO, TENANT_ID); + public static final List typedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, ADDITIONAL_INFO); + public static final List widgetEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME); public static final List commonEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, ADDITIONAL_INFO); - - public static final List dashboardEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE, TENANT_ID); - public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO, TENANT_ID, CUSTOMER_ID); + public static final List dashboardEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE); + public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO); public static final List contactBasedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, EMAIL, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO); - public static final Set apiUsageStateEntityFields = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME)); + public static final Set apiUsageStateEntityFields = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME)); public static final Set commonEntityFieldsSet = new HashSet<>(commonEntityFields); public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO)); static { allowedEntityFieldMap.put(EntityType.DEVICE, new HashSet<>(labeledEntityFields)); allowedEntityFieldMap.put(EntityType.ASSET, new HashSet<>(labeledEntityFields)); - allowedEntityFieldMap.put(EntityType.EDGE, new HashSet<>(labeledEntityFields)); allowedEntityFieldMap.put(EntityType.ENTITY_VIEW, new HashSet<>(typedEntityFields)); - allowedEntityFieldMap.get(EntityType.ENTITY_VIEW).add(CUSTOMER_ID); allowedEntityFieldMap.put(EntityType.TENANT, new HashSet<>(contactBasedEntityFields)); allowedEntityFieldMap.get(EntityType.TENANT).add(REGION); allowedEntityFieldMap.put(EntityType.CUSTOMER, new HashSet<>(contactBasedEntityFields)); - allowedEntityFieldMap.get(EntityType.CUSTOMER).add(TENANT_ID); - - allowedEntityFieldMap.put(EntityType.USER, new HashSet<>(Arrays.asList(CREATED_TIME, FIRST_NAME, LAST_NAME, EMAIL, - ADDITIONAL_INFO, AUTHORITY, TENANT_ID, CUSTOMER_ID))); - allowedEntityFieldMap.put(EntityType.DEVICE_PROFILE, new HashSet<>(commonEntityFields)); - allowedEntityFieldMap.get(EntityType.DEVICE_PROFILE).add(TENANT_ID); + allowedEntityFieldMap.put(EntityType.USER, new HashSet<>(Arrays.asList(CREATED_TIME, FIRST_NAME, LAST_NAME, EMAIL, ADDITIONAL_INFO))); allowedEntityFieldMap.put(EntityType.DASHBOARD, new HashSet<>(dashboardEntityFields)); allowedEntityFieldMap.put(EntityType.RULE_CHAIN, new HashSet<>(commonEntityFields)); - allowedEntityFieldMap.get(EntityType.RULE_CHAIN).add(TENANT_ID); - allowedEntityFieldMap.get(EntityType.RULE_CHAIN).add(TYPE); allowedEntityFieldMap.put(EntityType.RULE_NODE, new HashSet<>(commonEntityFields)); - allowedEntityFieldMap.put(EntityType.WIDGET_TYPE, new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TENANT_ID))); - allowedEntityFieldMap.put(EntityType.WIDGETS_BUNDLE, new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE, TENANT_ID))); + allowedEntityFieldMap.put(EntityType.WIDGET_TYPE, new HashSet<>(widgetEntityFields)); + allowedEntityFieldMap.put(EntityType.WIDGETS_BUNDLE, new HashSet<>(widgetEntityFields)); allowedEntityFieldMap.put(EntityType.API_USAGE_STATE, apiUsageStateEntityFields); - allowedEntityFieldMap.put(EntityType.TB_RESOURCE, Set.of(CREATED_TIME, ENTITY_TYPE, RESOURCE_TYPE, TITLE, TENANT_ID)); - allowedEntityFieldMap.put(EntityType.OTA_PACKAGE, Set.of(CREATED_TIME, ENTITY_TYPE, TYPE, TITLE, TENANT_ID)); entityFieldColumnMap.put(CREATED_TIME, ModelConstants.CREATED_TIME_PROPERTY); entityFieldColumnMap.put(ENTITY_TYPE, ModelConstants.ENTITY_TYPE_PROPERTY); @@ -139,42 +120,25 @@ public class EntityKeyMapping { entityFieldColumnMap.put(ZIP, ModelConstants.ZIP_PROPERTY); entityFieldColumnMap.put(PHONE, ModelConstants.PHONE_PROPERTY); entityFieldColumnMap.put(ADDITIONAL_INFO, ModelConstants.ADDITIONAL_INFO_PROPERTY); - entityFieldColumnMap.put(TENANT_ID, ModelConstants.TENANT_ID_PROPERTY); - entityFieldColumnMap.put(CUSTOMER_ID, ModelConstants.CUSTOMER_ID_PROPERTY); - entityFieldColumnMap.put(AUTHORITY, ModelConstants.USER_AUTHORITY_PROPERTY); - entityFieldColumnMap.put(RESOURCE_TYPE, ModelConstants.RESOURCE_TYPE_COLUMN); Map contactBasedAliases = new HashMap<>(); contactBasedAliases.put(NAME, TITLE); contactBasedAliases.put(LABEL, TITLE); aliases.put(EntityType.TENANT, contactBasedAliases); - aliases.put(EntityType.CUSTOMER, new HashMap<>(contactBasedAliases)); + aliases.put(EntityType.CUSTOMER, contactBasedAliases); aliases.put(EntityType.DASHBOARD, contactBasedAliases); Map commonEntityAliases = new HashMap<>(); commonEntityAliases.put(TITLE, NAME); aliases.put(EntityType.DEVICE, commonEntityAliases); aliases.put(EntityType.ASSET, commonEntityAliases); aliases.put(EntityType.ENTITY_VIEW, commonEntityAliases); - aliases.put(EntityType.EDGE, commonEntityAliases); - aliases.put(EntityType.WIDGETS_BUNDLE, new HashMap<>(commonEntityAliases)); - aliases.get(EntityType.WIDGETS_BUNDLE).put(NAME, TITLE); + aliases.put(EntityType.WIDGETS_BUNDLE, commonEntityAliases); Map userEntityAliases = new HashMap<>(); userEntityAliases.put(TITLE, EMAIL); userEntityAliases.put(LABEL, EMAIL); userEntityAliases.put(NAME, EMAIL); - userEntityAliases.put(TYPE, AUTHORITY); aliases.put(EntityType.USER, userEntityAliases); - aliases.put(EntityType.TB_RESOURCE, Map.of(NAME, TITLE, TYPE, RESOURCE_TYPE)); - aliases.put(EntityType.OTA_PACKAGE, Map.of(NAME, TITLE)); - - propertiesFunctions.put(EntityType.USER, Map.of( - LAST_ACTIVITY_TIME, "cast(e.additional_info::json ->> 'lastLoginTs' as bigint)" - )); - - Arrays.stream(EntityType.values()).forEach(entityType -> { - searchTextFields.put(entityType, ModelConstants.SEARCH_TEXT_PROPERTY); - }); } private int index; @@ -215,10 +179,6 @@ public class EntityKeyMapping { String column = entityFieldColumnMap.get(alias); return String.format("cast(e.%s as varchar) as %s", column, getValueAlias()); } else { - Map entityPropertiesFunctions = propertiesFunctions.get(entityType); - if (entityPropertiesFunctions != null && entityPropertiesFunctions.containsKey(alias)) { - return String.format("%s as %s", entityPropertiesFunctions.get(alias), getValueAlias()); - } return String.format("'' as %s", getValueAlias()); } } From 3abf323a1ea4d0d0cabfd47b8bf568a45ae4c244 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 5 Nov 2021 18:51:04 +0200 Subject: [PATCH 222/303] UI: Remove invalid JSON form fields in the time series table --- application/src/main/data/json/system/widget_bundles/cards.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 41aed542dd..9b70d91a08 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -55,7 +55,7 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n ignoreDataUpdateOnIntervalTick: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"enableSearch\": {\n \"title\": \"Enable search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showMilliseconds\": {\n \"title\": \"Display timestamp milliseconds\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n }, \n \"useEntityLabel\": {\n \"title\": \"Use entity label in tab name\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"hideEmptyLines\": {\n \"title\": \"Hide empty lines\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"disableStickyHeader\": {\n \"title\": \"Disable sticky header\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"enableSearch\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"showTimestamp\",\n \"showMilliseconds\",\n \"displayPagination\",\n \"useEntityLabel\",\n \"defaultPageSize\",\n \"identifyDeviceSelector\",\n \"hideEmptyLines\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"enableSearch\": {\n \"title\": \"Enable search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showMilliseconds\": {\n \"title\": \"Display timestamp milliseconds\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n }, \n \"useEntityLabel\": {\n \"title\": \"Use entity label in tab name\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"hideEmptyLines\": {\n \"title\": \"Hide empty lines\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"disableStickyHeader\": {\n \"title\": \"Disable sticky header\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"enableSearch\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"showTimestamp\",\n \"showMilliseconds\",\n \"displayPagination\",\n \"useEntityLabel\",\n \"defaultPageSize\",\n \"hideEmptyLines\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n }\n ]\n}", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\"}" } From d511bd22a4da5a9416c8bb62b438f8f9fefcfaaa Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Sat, 6 Nov 2021 16:42:25 +0200 Subject: [PATCH 223/303] Remove redundant length constraint for comment field --- .../common/data/oauth2/OAuth2ClientRegistrationTemplate.java | 1 - 1 file changed, 1 deletion(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java index f4baef2abb..b4070313e8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java @@ -62,7 +62,6 @@ public class OAuth2ClientRegistrationTemplate extends SearchTextBasedWithAdditio @Length(fieldName = "clientAuthenticationMethod") @ApiModelProperty(value = "Default client authentication method to use: 'BASIC' or 'POST'") private String clientAuthenticationMethod; - @Length(fieldName = "comment") @ApiModelProperty(value = "Comment for OAuth2 provider") private String comment; @Length(fieldName = "loginButtonIcon") From 541110b3445d109185641c089c086e9aa6fc6d67 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Fri, 5 Nov 2021 18:29:38 +0200 Subject: [PATCH 224/303] fixed concurrency exception when deleting relation --- .../dao/sql/relation/JpaRelationDao.java | 6 +++++- .../dao/service/BaseRelationServiceTest.java | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 91cc1a0c9f..2eaa5c28a2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -157,7 +157,11 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple private boolean deleteRelationIfExists(RelationCompositeKey key) { boolean relationExistsBeforeDelete = relationRepository.existsById(key); if (relationExistsBeforeDelete) { - relationRepository.deleteById(key); + try { + relationRepository.deleteById(key); + } catch (ConcurrencyFailureException e) { + log.debug("[{}] Concurrency exception while deleting relation", key, e); + } } return relationExistsBeforeDelete; } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java index 6f5ea9acb9..27dc7f812a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java @@ -16,6 +16,8 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -31,6 +33,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.dao.exception.DataValidationException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; @@ -84,6 +87,23 @@ public abstract class BaseRelationServiceTest extends AbstractServiceTest { Assert.assertTrue(relationService.deleteRelationAsync(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON).get()); } + @Test + public void testDeleteRelationConcurrently() throws ExecutionException, InterruptedException { + AssetId parentId = new AssetId(Uuids.timeBased()); + AssetId childId = new AssetId(Uuids.timeBased()); + + EntityRelation relationA = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); + + saveRelation(relationA); + + List> futures = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + futures.add(relationService.deleteRelationAsync(SYSTEM_TENANT_ID, relationA)); + } + List results = Futures.allAsList(futures).get(); + Assert.assertTrue(results.contains(true)); + } + @Test public void testDeleteEntityRelations() throws ExecutionException, InterruptedException { AssetId parentId = new AssetId(Uuids.timeBased()); From 30acfd44e0fa1f06989541f34dfee2c012fd6193 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 5 Nov 2021 19:35:06 +0200 Subject: [PATCH 225/303] PaginateUpdater info log added on start updateEntities --- .../server/service/install/update/PaginatedUpdater.java | 1 + 1 file changed, 1 insertion(+) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java b/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java index 768d627a16..c10d1b4bd7 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java @@ -28,6 +28,7 @@ public abstract class PaginatedUpdater { private int updated = 0; public void updateEntities(I id) { + log.info("{}: started...", getName()); updated = 0; PageLink pageLink = new PageLink(DEFAULT_LIMIT); boolean hasNext = true; From 3003ee6e08b817f703ed9ded81a25a94d2bceced Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 5 Nov 2021 19:36:21 +0200 Subject: [PATCH 226/303] TimePageLink callSuper = true for ToString and EqualsAndHashCode --- .../org/thingsboard/server/common/data/page/TimePageLink.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java b/common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java index 879db38218..be4878b50e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java @@ -17,8 +17,12 @@ package org.thingsboard.server.common.data.page; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; @Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) public class TimePageLink extends PageLink { private final Long startTime; From b477328dd3e180c3e0f5569ab68b230340ec7487 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 8 Nov 2021 08:41:26 +0200 Subject: [PATCH 227/303] updater: verbose updateTenantAlarmsCustomer processed count --- .../install/update/DefaultDataUpdateService.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 3172c37af6..b4e7794e2d 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -63,6 +63,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isBlank; @@ -382,6 +383,8 @@ public class DefaultDataUpdateService implements DataUpdateService { private final PaginatedUpdater tenantsAlarmsCustomerUpdater = new PaginatedUpdater<>() { + final AtomicLong processed = new AtomicLong(); + @Override protected String getName() { return "Tenants alarms customer updater"; @@ -399,12 +402,12 @@ public class DefaultDataUpdateService implements DataUpdateService { @Override protected void updateEntity(Tenant tenant) { - updateTenantAlarmsCustomer(tenant.getId()); + updateTenantAlarmsCustomer(tenant.getId(), getName(), processed); } }; - private void updateTenantAlarmsCustomer(TenantId tenantId) { - AlarmQuery alarmQuery = new AlarmQuery(null, new TimePageLink(100), null, null, false); + private void updateTenantAlarmsCustomer(TenantId tenantId, String name, AtomicLong processed) { + AlarmQuery alarmQuery = new AlarmQuery(null, new TimePageLink(1000), null, null, false); PageData alarms = alarmDao.findAlarms(tenantId, alarmQuery); boolean hasNext = true; while (hasNext) { @@ -413,6 +416,9 @@ public class DefaultDataUpdateService implements DataUpdateService { alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator())); alarmDao.save(tenantId, alarm); } + if (processed.incrementAndGet() % 1000 == 0) { + log.info("{}: {} processed so far...", name, processed); + } } if (alarms.hasNext()) { alarmQuery.setPageLink(alarmQuery.getPageLink().nextPageLink()); From 27d745f1e3a95bc2537ea6cb1b89e508bf4ede06 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 8 Nov 2021 10:47:27 +0200 Subject: [PATCH 228/303] tests added for update service for convertDeviceProfileAlarmRulesForVersion330 --- .../update/DefaultDataUpdateService.java | 55 ++--- .../update/DefaultDataUpdateServiceTest.java | 97 +++++++++ .../src/test/resources/update/330/README.md | 3 + .../update/330/device_profile_001_in.json | 173 ++++++++++++++++ .../update/330/device_profile_001_out.json | 189 ++++++++++++++++++ 5 files changed, 491 insertions(+), 26 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/service/install/update/DefaultDataUpdateServiceTest.java create mode 100644 application/src/test/resources/update/330/README.md create mode 100644 application/src/test/resources/update/330/device_profile_001_in.json create mode 100644 application/src/test/resources/update/330/device_profile_001_out.json diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index b4e7794e2d..ebdf60e7b7 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -145,35 +145,38 @@ public class DefaultDataUpdateService implements DataUpdateService { @Override protected void updateEntity(DeviceProfileEntity deviceProfile) { - if (deviceProfile.getProfileData().has("alarms") && - !deviceProfile.getProfileData().get("alarms").isNull()) { - boolean isUpdated = false; - JsonNode alarms = deviceProfile.getProfileData().get("alarms"); - for (JsonNode alarm : alarms) { - if (alarm.has("createRules")) { - JsonNode createRules = alarm.get("createRules"); - for (AlarmSeverity severity : AlarmSeverity.values()) { - if (createRules.has(severity.name())) { - JsonNode spec = createRules.get(severity.name()).get("condition").get("spec"); - if (convertDeviceProfileAlarmRulesForVersion330(spec)) { - isUpdated = true; - } - } - } - } - if (alarm.has("clearRule") && !alarm.get("clearRule").isNull()) { - JsonNode spec = alarm.get("clearRule").get("condition").get("spec"); - if (convertDeviceProfileAlarmRulesForVersion330(spec)) { - isUpdated = true; - } + if (convertDeviceProfileForVersion330(deviceProfile.getProfileData())) { + deviceProfileRepository.save(deviceProfile); + } + } + }; + + boolean convertDeviceProfileForVersion330(JsonNode profileData) { + boolean isUpdated = false; + if (profileData.has("alarms") && !profileData.get("alarms").isNull()) { + JsonNode alarms = profileData.get("alarms"); + for (JsonNode alarm : alarms) { + if (alarm.has("createRules")) { + JsonNode createRules = alarm.get("createRules"); + for (AlarmSeverity severity : AlarmSeverity.values()) { + if (createRules.has(severity.name())) { + JsonNode spec = createRules.get(severity.name()).get("condition").get("spec"); + if (convertDeviceProfileAlarmRulesForVersion330(spec)) { + isUpdated = true; } } - if (isUpdated) { - deviceProfileRepository.save(deviceProfile); - } } } - }; + if (alarm.has("clearRule") && !alarm.get("clearRule").isNull()) { + JsonNode spec = alarm.get("clearRule").get("condition").get("spec"); + if (convertDeviceProfileAlarmRulesForVersion330(spec)) { + isUpdated = true; + } + } + } + } + return isUpdated; + } private final PaginatedUpdater tenantsDefaultRuleChainUpdater = new PaginatedUpdater<>() { @@ -429,7 +432,7 @@ public class DefaultDataUpdateService implements DataUpdateService { } } - private boolean convertDeviceProfileAlarmRulesForVersion330(JsonNode spec) { + boolean convertDeviceProfileAlarmRulesForVersion330(JsonNode spec) { if (spec != null) { if (spec.has("type") && spec.get("type").asText().equals("DURATION")) { if (spec.has("value")) { diff --git a/application/src/test/java/org/thingsboard/server/service/install/update/DefaultDataUpdateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/install/update/DefaultDataUpdateServiceTest.java new file mode 100644 index 0000000000..2a37fa7c2a --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/install/update/DefaultDataUpdateServiceTest.java @@ -0,0 +1,97 @@ +/** + * Copyright © 2016-2021 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.install.update; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ActiveProfiles; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.willCallRealMethod; + +@ActiveProfiles("install") +@SpringBootTest(classes = DefaultDataUpdateService.class) +class DefaultDataUpdateServiceTest { + + ObjectMapper mapper = new ObjectMapper(); + + @MockBean + DefaultDataUpdateService service; + + @BeforeEach + void setUp() { + willCallRealMethod().given(service).convertDeviceProfileAlarmRulesForVersion330(any()); + willCallRealMethod().given(service).convertDeviceProfileForVersion330(any()); + } + + JsonNode readFromResource(String resourceName) throws IOException { + return mapper.readTree(this.getClass().getClassLoader().getResourceAsStream(resourceName)); + } + + @Test + void convertDeviceProfileAlarmRulesForVersion330FirstRun() throws IOException { + JsonNode spec = readFromResource("update/330/device_profile_001_in.json"); + JsonNode expected = readFromResource("update/330/device_profile_001_out.json"); + + assertThat(service.convertDeviceProfileForVersion330(spec.get("profileData"))).isTrue(); + assertThat(spec.toPrettyString()).isEqualTo(expected.toPrettyString()); // use IDE feature + } + + @Test + void convertDeviceProfileAlarmRulesForVersion330SecondRun() throws IOException { + JsonNode spec = readFromResource("update/330/device_profile_001_out.json"); + JsonNode expected = readFromResource("update/330/device_profile_001_out.json"); + + assertThat(service.convertDeviceProfileForVersion330(spec.get("profileData"))).isFalse(); + assertThat(spec.toPrettyString()).isEqualTo(expected.toPrettyString()); // use IDE feature + } + + @Test + void convertDeviceProfileAlarmRulesForVersion330EmptyJson() throws JsonProcessingException { + JsonNode spec = mapper.readTree("{ }"); + JsonNode expected = mapper.readTree("{ }"); + + assertThat(service.convertDeviceProfileForVersion330(spec)).isFalse(); + assertThat(spec.toPrettyString()).isEqualTo(expected.toPrettyString()); + } + + @Test + void convertDeviceProfileAlarmRulesForVersion330AlarmNodeNull() throws JsonProcessingException { + JsonNode spec = mapper.readTree("{ \"alarms\" : null }"); + JsonNode expected = mapper.readTree("{ \"alarms\" : null }"); + + assertThat(service.convertDeviceProfileForVersion330(spec)).isFalse(); + assertThat(spec.toPrettyString()).isEqualTo(expected.toPrettyString()); + } + + @Test + void convertDeviceProfileAlarmRulesForVersion330NoAlarmNode() throws JsonProcessingException { + JsonNode spec = mapper.readTree("{ \"configuration\": { \"type\": \"DEFAULT\" } }"); + JsonNode expected = mapper.readTree("{ \"configuration\": { \"type\": \"DEFAULT\" } }"); + + assertThat(service.convertDeviceProfileForVersion330(spec)).isFalse(); + assertThat(spec.toPrettyString()).isEqualTo(expected.toPrettyString()); + } + +} diff --git a/application/src/test/resources/update/330/README.md b/application/src/test/resources/update/330/README.md new file mode 100644 index 0000000000..26c5e74898 --- /dev/null +++ b/application/src/test/resources/update/330/README.md @@ -0,0 +1,3 @@ +To get json from live Thingsboard instance use those methods: +1. Browser: F12 -> Network -> open device profile page -> copy raw response +2. Database: SELECT * FROM public.device_profile WHERE name = 'LORAWAN 001'; \ No newline at end of file diff --git a/application/src/test/resources/update/330/device_profile_001_in.json b/application/src/test/resources/update/330/device_profile_001_in.json new file mode 100644 index 0000000000..16d1f09e43 --- /dev/null +++ b/application/src/test/resources/update/330/device_profile_001_in.json @@ -0,0 +1,173 @@ +{ + "id": { + "entityType": "DEVICE_PROFILE", + "id": "b99fde7a-33dd-4d5d-a325-d0637f6acbe5" + }, + "createdTime": 1627268171906, + "tenantId": { + "entityType": "TENANT", + "id": "3db30ac6-db03-4788-98fe-6e024b422a15" + }, + "name": "LORAWAN 001", + "description": "Tektelic - 001", + "type": "DEFAULT", + "transportType": "DEFAULT", + "provisionType": "DISABLED", + "defaultRuleChainId": { + "entityType": "RULE_CHAIN", + "id": "9c50f4df-f41e-443f-bb7d-37b5ac97f3c3" + }, + "defaultQueueName": "LORAWAN", + "profileData": { + "configuration": { + "type": "DEFAULT" + }, + "transportConfiguration": { + "type": "DEFAULT" + }, + "provisionConfiguration": { + "type": "DISABLED", + "provisionDeviceSecret": null + }, + "alarms": [ + { + "id": "b86271fd-5fee-4bd5-975c-d9c18f610cd5", + "alarmType": "LORAWAN - Battery Alarm", + "createRules": { + "CRITICAL": { + "condition": { + "condition": [ + { + "key": { + "type": "TIME_SERIES", + "key": "batteryLevel" + }, + "valueType": "NUMERIC", + "value": null, + "predicate": { + "type": "NUMERIC", + "operation": "LESS", + "value": { + "defaultValue": 25.0, + "userValue": null, + "dynamicValue": null + } + } + } + ], + "spec": { + "type": "DURATION", + "unit": "DAYS", + "value": 1 + } + }, + "schedule": null, + "alarmDetails": null + } + }, + "clearRule": { + "condition": { + "condition": [ + { + "key": { + "type": "TIME_SERIES", + "key": "batteryLevel" + }, + "valueType": "NUMERIC", + "value": null, + "predicate": { + "type": "NUMERIC", + "operation": "GREATER_OR_EQUAL", + "value": { + "defaultValue": 25.0, + "userValue": null, + "dynamicValue": null + } + } + } + ], + "spec": { + "type": "DURATION", + "unit": "DAYS", + "value": 1 + } + }, + "schedule": null, + "alarmDetails": null + }, + "propagate": true, + "propagateRelationTypes": [ + "UC-0007 LORAWAN" + ] + }, + { + "id": "c70aef4e-65cf-4578-acd9-e1927c08b469", + "alarmType": "LORAWAN - No Data", + "createRules": { + "CRITICAL": { + "condition": { + "condition": [ + { + "key": { + "type": "TIME_SERIES", + "key": "active" + }, + "valueType": "BOOLEAN", + "value": null, + "predicate": { + "type": "BOOLEAN", + "operation": "EQUAL", + "value": { + "defaultValue": false, + "userValue": null, + "dynamicValue": null + } + } + } + ], + "spec": { + "type": "SIMPLE" + } + }, + "schedule": null, + "alarmDetails": null + } + }, + "clearRule": { + "condition": { + "condition": [ + { + "key": { + "type": "TIME_SERIES", + "key": "active" + }, + "valueType": "BOOLEAN", + "value": null, + "predicate": { + "type": "BOOLEAN", + "operation": "EQUAL", + "value": { + "defaultValue": true, + "userValue": null, + "dynamicValue": null + } + } + } + ], + "spec": { + "type": "SIMPLE" + } + }, + "schedule": null, + "alarmDetails": null + }, + "propagate": true, + "propagateRelationTypes": [ + "LORAWAN 001 related" + ] + } + ] + }, + "provisionDeviceKey": null, + "default": false +} diff --git a/application/src/test/resources/update/330/device_profile_001_out.json b/application/src/test/resources/update/330/device_profile_001_out.json new file mode 100644 index 0000000000..9a349c6638 --- /dev/null +++ b/application/src/test/resources/update/330/device_profile_001_out.json @@ -0,0 +1,189 @@ +{ + "id": { + "entityType": "DEVICE_PROFILE", + "id": "b99fde7a-33dd-4d5d-a325-d0637f6acbe5" + }, + "createdTime": 1627268171906, + "tenantId": { + "entityType": "TENANT", + "id": "3db30ac6-db03-4788-98fe-6e024b422a15" + }, + "name": "LORAWAN 001", + "description": "Tektelic - 001", + "type": "DEFAULT", + "transportType": "DEFAULT", + "provisionType": "DISABLED", + "defaultRuleChainId": { + "entityType": "RULE_CHAIN", + "id": "9c50f4df-f41e-443f-bb7d-37b5ac97f3c3" + }, + "defaultQueueName": "LORAWAN", + "profileData": { + "configuration": { + "type": "DEFAULT" + }, + "transportConfiguration": { + "type": "DEFAULT" + }, + "provisionConfiguration": { + "type": "DISABLED", + "provisionDeviceSecret": null + }, + "alarms": [ + { + "id": "b86271fd-5fee-4bd5-975c-d9c18f610cd5", + "alarmType": "LORAWAN - Battery Alarm", + "createRules": { + "CRITICAL": { + "condition": { + "condition": [ + { + "key": { + "type": "TIME_SERIES", + "key": "batteryLevel" + }, + "valueType": "NUMERIC", + "value": null, + "predicate": { + "type": "NUMERIC", + "operation": "LESS", + "value": { + "defaultValue": 25.0, + "userValue": null, + "dynamicValue": null + } + } + } + ], + "spec": { + "type": "DURATION", + "unit": "DAYS", + "predicate": { + "defaultValue": 1, + "userValue": null, + "dynamicValue": { + "sourceType": null, + "sourceAttribute": null, + "inherit": false + } + } + } + }, + "schedule": null, + "alarmDetails": null + } + }, + "clearRule": { + "condition": { + "condition": [ + { + "key": { + "type": "TIME_SERIES", + "key": "batteryLevel" + }, + "valueType": "NUMERIC", + "value": null, + "predicate": { + "type": "NUMERIC", + "operation": "GREATER_OR_EQUAL", + "value": { + "defaultValue": 25.0, + "userValue": null, + "dynamicValue": null + } + } + } + ], + "spec": { + "type": "DURATION", + "unit": "DAYS", + "predicate": { + "defaultValue": 1, + "userValue": null, + "dynamicValue": { + "sourceType": null, + "sourceAttribute": null, + "inherit": false + } + } + } + }, + "schedule": null, + "alarmDetails": null + }, + "propagate": true, + "propagateRelationTypes": [ + "UC-0007 LORAWAN" + ] + }, + { + "id": "c70aef4e-65cf-4578-acd9-e1927c08b469", + "alarmType": "LORAWAN - No Data", + "createRules": { + "CRITICAL": { + "condition": { + "condition": [ + { + "key": { + "type": "TIME_SERIES", + "key": "active" + }, + "valueType": "BOOLEAN", + "value": null, + "predicate": { + "type": "BOOLEAN", + "operation": "EQUAL", + "value": { + "defaultValue": false, + "userValue": null, + "dynamicValue": null + } + } + } + ], + "spec": { + "type": "SIMPLE" + } + }, + "schedule": null, + "alarmDetails": null + } + }, + "clearRule": { + "condition": { + "condition": [ + { + "key": { + "type": "TIME_SERIES", + "key": "active" + }, + "valueType": "BOOLEAN", + "value": null, + "predicate": { + "type": "BOOLEAN", + "operation": "EQUAL", + "value": { + "defaultValue": true, + "userValue": null, + "dynamicValue": null + } + } + } + ], + "spec": { + "type": "SIMPLE" + } + }, + "schedule": null, + "alarmDetails": null + }, + "propagate": true, + "propagateRelationTypes": [ + "LORAWAN 001 related" + ] + } + ] + }, + "provisionDeviceKey": null, + "default": false +} From 0db0bb8607bd13b00384d3a04d9e675fd317e6c7 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 8 Nov 2021 11:44:38 +0200 Subject: [PATCH 229/303] fix coap efento callbacks --- .../server/transport/coap/callback/CoapEfentoCallback.java | 5 ++--- .../transport/coap/efento/CoapEfentoTransportResource.java | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapEfentoCallback.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapEfentoCallback.java index f2387bf0d1..efda6f3efe 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapEfentoCallback.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/callback/CoapEfentoCallback.java @@ -34,10 +34,9 @@ public class CoapEfentoCallback implements TransportServiceCallback { @Override public void onSuccess(Void msg) { + //We respond only to confirmed requests in order to reduce battery consumption for Efento devices. if (isConRequest()) { - Response response = new Response(onSuccessResponse); - response.setAcknowledged(true); - exchange.respond(response); + exchange.respond(new Response(onSuccessResponse)); } } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java index 06395109d1..6fea53f48a 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java @@ -99,10 +99,9 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { break; case DEVICE_INFO: case CONFIGURATION: - Response response = new Response(CoAP.ResponseCode.CREATED); + //We respond only to confirmed requests in order to reduce battery consumption for Efento devices. if (exchange.advanced().getRequest().isConfirmable()) { - response.setAcknowledged(true); - exchange.respond(response); + exchange.respond(new Response(CoAP.ResponseCode.CREATED)); } break; default: From 037d1797accb623539b23494fc31146bcd169d78 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 8 Nov 2021 10:43:22 +0200 Subject: [PATCH 230/303] Fix for mqtt duplication sending on sent failed --- .../src/main/java/org/thingsboard/mqtt/MqttClientImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java index fdc44dbb42..827d9fa4cf 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java @@ -368,6 +368,7 @@ final class MqttClientImpl implements MqttClient { if (channelFuture != null) { pendingPublish.setSent(true); if (channelFuture.cause() != null) { + this.pendingPublishes.remove(pendingPublish.getMessageId()); future.setFailure(channelFuture.cause()); return future; } From e7c4e7685196d805faebb0e28260a163c7c224d9 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 8 Nov 2021 12:59:42 +0200 Subject: [PATCH 231/303] Added removing for timers in pendingPublishes on channel is closed --- .../org/thingsboard/mqtt/MqttClientImpl.java | 32 +++++++++++-------- .../thingsboard/mqtt/MqttPendingPublish.java | 5 +++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java index 827d9fa4cf..5fbdb883af 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java @@ -55,6 +55,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; /** * Represents an MqttClientImpl connected to a single MQTT server. Will try to keep the connection going at all times @@ -160,6 +161,7 @@ final class MqttClientImpl implements MqttClient { subscriptions.clear(); pendingServerUnsubscribes.clear(); qos2PendingIncomingPublishes.clear(); + pendingPublishes.forEach((id, mqttPendingPublish) -> mqttPendingPublish.onChannelClosed()); pendingPublishes.clear(); pendingSubscribeTopics.clear(); handlerToSubscribtion.clear(); @@ -366,20 +368,24 @@ final class MqttClientImpl implements MqttClient { ChannelFuture channelFuture = this.sendAndFlushPacket(message); if (channelFuture != null) { - pendingPublish.setSent(true); - if (channelFuture.cause() != null) { - this.pendingPublishes.remove(pendingPublish.getMessageId()); - future.setFailure(channelFuture.cause()); - return future; - } - } - if (pendingPublish.isSent() && pendingPublish.getQos() == MqttQoS.AT_MOST_ONCE) { - this.pendingPublishes.remove(pendingPublish.getMessageId()); - pendingPublish.getFuture().setSuccess(null); //We don't get an ACK for QOS 0 - } else if (pendingPublish.isSent()) { - pendingPublish.startPublishRetransmissionTimer(this.eventLoop.next(), this::sendAndFlushPacket); + channelFuture.addListener(result -> { + pendingPublish.setSent(true); + if (result.cause() != null) { + pendingPublishes.remove(pendingPublish.getMessageId()); + future.setFailure(result.cause()); + } else { + if (pendingPublish.isSent() && pendingPublish.getQos() == MqttQoS.AT_MOST_ONCE) { + pendingPublishes.remove(pendingPublish.getMessageId()); + pendingPublish.getFuture().setSuccess(null); //We don't get an ACK for QOS 0 + } else if (pendingPublish.isSent()) { + pendingPublish.startPublishRetransmissionTimer(eventLoop.next(), MqttClientImpl.this::sendAndFlushPacket); + } else { + pendingPublishes.remove(pendingPublish.getMessageId()); + } + } + }); } else { - this.pendingPublishes.remove(pendingPublish.getMessageId()); + pendingPublishes.remove(pendingPublish.getMessageId()); } return future; } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java index cedbd4556d..f647569553 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java @@ -98,4 +98,9 @@ final class MqttPendingPublish { void onPubcompReceived() { this.pubrelRetransmissionHandler.stop(); } + + void onChannelClosed() { + this.publishRetransmissionHandler.stop(); + this.pubrelRetransmissionHandler.stop(); + } } From 06f199b9362df2300ef95b5e55449f4d1fbb6ba3 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 8 Nov 2021 13:25:03 +0200 Subject: [PATCH 232/303] Added stopping for subscriptions handlers and for unsubscription handlers --- .../src/main/java/org/thingsboard/mqtt/MqttClientImpl.java | 2 ++ .../main/java/org/thingsboard/mqtt/MqttPendingPublish.java | 4 ++-- .../java/org/thingsboard/mqtt/MqttPendingSubscription.java | 6 +++++- .../org/thingsboard/mqtt/MqttPendingUnsubscription.java | 6 +++++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java index 5fbdb883af..f30fc6e6ad 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java @@ -156,9 +156,11 @@ final class MqttClientImpl implements MqttClient { if (callback != null) { callback.connectionLost(e); } + pendingSubscriptions.forEach((id, mqttPendingSubscription) -> mqttPendingSubscription.onChannelClosed()); pendingSubscriptions.clear(); serverSubscriptions.clear(); subscriptions.clear(); + pendingServerUnsubscribes.forEach((id, mqttPendingServerUnsubscribes) -> mqttPendingServerUnsubscribes.onChannelClosed()); pendingServerUnsubscribes.clear(); qos2PendingIncomingPublishes.clear(); pendingPublishes.forEach((id, mqttPendingPublish) -> mqttPendingPublish.onChannelClosed()); diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java index f647569553..e19a60226a 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java @@ -24,7 +24,7 @@ import io.netty.util.concurrent.Promise; import java.util.function.Consumer; -final class MqttPendingPublish { +final class MqttPendingPublish{ private final int messageId; private final Promise future; @@ -99,7 +99,7 @@ final class MqttPendingPublish { this.pubrelRetransmissionHandler.stop(); } - void onChannelClosed() { + void onChannelClosed(){ this.publishRetransmissionHandler.stop(); this.pubrelRetransmissionHandler.stop(); } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java index d0d396d784..975a399691 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java @@ -23,7 +23,7 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; -final class MqttPendingSubscription { +final class MqttPendingSubscription{ private final Promise future; private final String topic; @@ -99,4 +99,8 @@ final class MqttPendingSubscription { return once; } } + + void onChannelClosed(){ + this.retransmissionHandler.stop(); + } } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java index ca9d0b6e77..9042aa268a 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java @@ -21,7 +21,7 @@ import io.netty.util.concurrent.Promise; import java.util.function.Consumer; -final class MqttPendingUnsubscription { +final class MqttPendingUnsubscription{ private final Promise future; private final String topic; @@ -52,4 +52,8 @@ final class MqttPendingUnsubscription { void onUnsubackReceived(){ this.retransmissionHandler.stop(); } + + void onChannelClosed(){ + this.retransmissionHandler.stop(); + } } From 337f202812d6d0ad1e3bbbc525080ff3b748382f Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 8 Nov 2021 14:59:38 +0200 Subject: [PATCH 233/303] version upgrade: log detail added "alarm processed so far..." --- .../server/service/install/update/DefaultDataUpdateService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index ebdf60e7b7..de483dfda8 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -420,7 +420,7 @@ public class DefaultDataUpdateService implements DataUpdateService { alarmDao.save(tenantId, alarm); } if (processed.incrementAndGet() % 1000 == 0) { - log.info("{}: {} processed so far...", name, processed); + log.info("{}: {} alarms processed so far...", name, processed); } } if (alarms.hasNext()) { From 0468cf8cf5c6f0e9c21d1e9ff1e0b59662c612c0 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 8 Nov 2021 17:20:38 +0200 Subject: [PATCH 234/303] Fix duplication of MQTT packets in MQTT Client --- .../org/thingsboard/mqtt/MqttClientImpl.java | 9 ++++--- .../thingsboard/mqtt/MqttPendingPublish.java | 15 +++++++---- .../mqtt/MqttPendingSubscription.java | 15 +++++------ .../mqtt/MqttPendingUnsubscription.java | 5 ++-- .../thingsboard/mqtt/MqttSubscription.java | 6 ++--- .../thingsboard/mqtt/PendingOperation.java | 22 ++++++++++++++++ .../mqtt/RetransmissionHandler.java | 25 +++++++++++++------ 7 files changed, 70 insertions(+), 27 deletions(-) create mode 100644 netty-mqtt/src/main/java/org/thingsboard/mqtt/PendingOperation.java diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java index f30fc6e6ad..80a336cbb2 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java @@ -365,7 +365,8 @@ final class MqttClientImpl implements MqttClient { MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, false, qos, retain, 0); MqttPublishVariableHeader variableHeader = new MqttPublishVariableHeader(topic, getNewMessageId().messageId()); MqttPublishMessage message = new MqttPublishMessage(fixedHeader, variableHeader, payload); - MqttPendingPublish pendingPublish = new MqttPendingPublish(variableHeader.packetId(), future, payload.retain(), message, qos); + MqttPendingPublish pendingPublish = new MqttPendingPublish(variableHeader.packetId(), future, + payload.retain(), message, qos, () -> !pendingPublishes.containsKey(variableHeader.packetId())); this.pendingPublishes.put(pendingPublish.getMessageId(), pendingPublish); ChannelFuture channelFuture = this.sendAndFlushPacket(message); @@ -471,7 +472,8 @@ final class MqttClientImpl implements MqttClient { MqttSubscribePayload payload = new MqttSubscribePayload(Collections.singletonList(subscription)); MqttSubscribeMessage message = new MqttSubscribeMessage(fixedHeader, variableHeader, payload); - final MqttPendingSubscription pendingSubscription = new MqttPendingSubscription(future, topic, message); + final MqttPendingSubscription pendingSubscription = new MqttPendingSubscription(future, topic, message, + () -> !pendingSubscriptions.containsKey(variableHeader.messageId())); pendingSubscription.addHandler(handler, once); this.pendingSubscriptions.put(variableHeader.messageId(), pendingSubscription); this.pendingSubscribeTopics.add(topic); @@ -489,7 +491,8 @@ final class MqttClientImpl implements MqttClient { MqttUnsubscribePayload payload = new MqttUnsubscribePayload(Collections.singletonList(topic)); MqttUnsubscribeMessage message = new MqttUnsubscribeMessage(fixedHeader, variableHeader, payload); - MqttPendingUnsubscription pendingUnsubscription = new MqttPendingUnsubscription(promise, topic, message); + MqttPendingUnsubscription pendingUnsubscription = new MqttPendingUnsubscription(promise, topic, message, + () -> !pendingServerUnsubscribes.containsKey(variableHeader.messageId())); this.pendingServerUnsubscribes.put(variableHeader.messageId(), pendingUnsubscription); pendingUnsubscription.startRetransmissionTimer(this.eventLoop.next(), this::sendAndFlushPacket); diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java index e19a60226a..8369d8f65e 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java @@ -24,7 +24,7 @@ import io.netty.util.concurrent.Promise; import java.util.function.Consumer; -final class MqttPendingPublish{ +final class MqttPendingPublish { private final int messageId; private final Promise future; @@ -32,19 +32,21 @@ final class MqttPendingPublish{ private final MqttPublishMessage message; private final MqttQoS qos; - private final RetransmissionHandler publishRetransmissionHandler = new RetransmissionHandler<>(); - private final RetransmissionHandler pubrelRetransmissionHandler = new RetransmissionHandler<>(); + private final RetransmissionHandler publishRetransmissionHandler; + private final RetransmissionHandler pubrelRetransmissionHandler; private boolean sent = false; - MqttPendingPublish(int messageId, Promise future, ByteBuf payload, MqttPublishMessage message, MqttQoS qos) { + MqttPendingPublish(int messageId, Promise future, ByteBuf payload, MqttPublishMessage message, MqttQoS qos, PendingOperation operation) { this.messageId = messageId; this.future = future; this.payload = payload; this.message = message; this.qos = qos; + this.publishRetransmissionHandler = new RetransmissionHandler<>(operation); this.publishRetransmissionHandler.setOriginalMessage(message); + this.pubrelRetransmissionHandler = new RetransmissionHandler<>(operation); } int getMessageId() { @@ -99,8 +101,11 @@ final class MqttPendingPublish{ this.pubrelRetransmissionHandler.stop(); } - void onChannelClosed(){ + void onChannelClosed() { this.publishRetransmissionHandler.stop(); this.pubrelRetransmissionHandler.stop(); + if (payload != null) { + payload.release(); + } } } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java index 975a399691..17bfa1139d 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java @@ -23,22 +23,23 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; -final class MqttPendingSubscription{ +final class MqttPendingSubscription { private final Promise future; private final String topic; private final Set handlers = new HashSet<>(); private final MqttSubscribeMessage subscribeMessage; - private final RetransmissionHandler retransmissionHandler = new RetransmissionHandler<>(); + private final RetransmissionHandler retransmissionHandler; private boolean sent = false; - MqttPendingSubscription(Promise future, String topic, MqttSubscribeMessage message) { + MqttPendingSubscription(Promise future, String topic, MqttSubscribeMessage message, PendingOperation operation) { this.future = future; this.topic = topic; this.subscribeMessage = message; + this.retransmissionHandler = new RetransmissionHandler<>(operation); this.retransmissionHandler.setOriginalMessage(message); } @@ -62,7 +63,7 @@ final class MqttPendingSubscription{ return subscribeMessage; } - void addHandler(MqttHandler handler, boolean once){ + void addHandler(MqttHandler handler, boolean once) { this.handlers.add(new MqttPendingHandler(handler, once)); } @@ -71,14 +72,14 @@ final class MqttPendingSubscription{ } void startRetransmitTimer(EventLoop eventLoop, Consumer sendPacket) { - if(this.sent){ //If the packet is sent, we can start the retransmit timer + if (this.sent) { //If the packet is sent, we can start the retransmit timer this.retransmissionHandler.setHandle((fixedHeader, originalMessage) -> sendPacket.accept(new MqttSubscribeMessage(fixedHeader, originalMessage.variableHeader(), originalMessage.payload()))); this.retransmissionHandler.start(eventLoop); } } - void onSubackReceived(){ + void onSubackReceived() { this.retransmissionHandler.stop(); } @@ -100,7 +101,7 @@ final class MqttPendingSubscription{ } } - void onChannelClosed(){ + void onChannelClosed() { this.retransmissionHandler.stop(); } } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java index 9042aa268a..42d2b852b9 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java @@ -26,12 +26,13 @@ final class MqttPendingUnsubscription{ private final Promise future; private final String topic; - private final RetransmissionHandler retransmissionHandler = new RetransmissionHandler<>(); + private final RetransmissionHandler retransmissionHandler; - MqttPendingUnsubscription(Promise future, String topic, MqttUnsubscribeMessage unsubscribeMessage) { + MqttPendingUnsubscription(Promise future, String topic, MqttUnsubscribeMessage unsubscribeMessage, PendingOperation operation) { this.future = future; this.topic = topic; + this.retransmissionHandler = new RetransmissionHandler<>(operation); this.retransmissionHandler.setOriginalMessage(unsubscribeMessage); } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java index 9f06ff84e4..62b5e059f4 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java @@ -28,10 +28,10 @@ final class MqttSubscription { private boolean called; MqttSubscription(String topic, MqttHandler handler, boolean once) { - if(topic == null){ + if (topic == null) { throw new NullPointerException("topic"); } - if(handler == null){ + if (handler == null) { throw new NullPointerException("handler"); } this.topic = topic; @@ -56,7 +56,7 @@ final class MqttSubscription { return called; } - boolean matches(String topic){ + boolean matches(String topic) { return this.topicRegex.matcher(topic).matches(); } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/PendingOperation.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/PendingOperation.java new file mode 100644 index 0000000000..c9ab7c5f5e --- /dev/null +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/PendingOperation.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2021 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.mqtt; + +public interface PendingOperation { + + boolean isCanceled(); + +} diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/RetransmissionHandler.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/RetransmissionHandler.java index 531d3bf19a..5d3f9b39d6 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/RetransmissionHandler.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/RetransmissionHandler.java @@ -21,33 +21,43 @@ import io.netty.handler.codec.mqtt.MqttMessage; import io.netty.handler.codec.mqtt.MqttMessageType; import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.util.concurrent.ScheduledFuture; +import lombok.RequiredArgsConstructor; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; +@RequiredArgsConstructor final class RetransmissionHandler { + private volatile boolean stopped; + private final PendingOperation pendingOperation; private ScheduledFuture timer; private int timeout = 10; private BiConsumer handler; private T originalMessage; - void start(EventLoop eventLoop){ - if(eventLoop == null){ + void start(EventLoop eventLoop) { + if (eventLoop == null) { throw new NullPointerException("eventLoop"); } - if(this.handler == null){ + if (this.handler == null) { throw new NullPointerException("handler"); } this.timeout = 10; this.startTimer(eventLoop); } - private void startTimer(EventLoop eventLoop){ + private void startTimer(EventLoop eventLoop) { + if (stopped || pendingOperation.isCanceled()) { + return; + } this.timer = eventLoop.schedule(() -> { + if (stopped || pendingOperation.isCanceled()) { + return; + } this.timeout += 5; boolean isDup = this.originalMessage.fixedHeader().isDup(); - if(this.originalMessage.fixedHeader().messageType() == MqttMessageType.PUBLISH && this.originalMessage.fixedHeader().qosLevel() != MqttQoS.AT_MOST_ONCE){ + if (this.originalMessage.fixedHeader().messageType() == MqttMessageType.PUBLISH && this.originalMessage.fixedHeader().qosLevel() != MqttQoS.AT_MOST_ONCE) { isDup = true; } MqttFixedHeader fixedHeader = new MqttFixedHeader(this.originalMessage.fixedHeader().messageType(), isDup, this.originalMessage.fixedHeader().qosLevel(), this.originalMessage.fixedHeader().isRetain(), this.originalMessage.fixedHeader().remainingLength()); @@ -56,8 +66,9 @@ final class RetransmissionHandler { }, timeout, TimeUnit.SECONDS); } - void stop(){ - if(this.timer != null){ + void stop() { + stopped = true; + if (this.timer != null) { this.timer.cancel(true); } } From de44eb44405940c46489fa48835b54f8c9d9befc Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 8 Nov 2021 15:31:47 +0200 Subject: [PATCH 235/303] UI: Improvement style for mqtt transport settings in device profile --- .../mqtt-device-profile-transport-configuration.component.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.scss b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.scss index d1a270602e..4e464f5e49 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.scss +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.scss @@ -24,8 +24,9 @@ color: rgba(0, 0, 0, .7); } - .tb-hint{ + .tb-hint { padding: 0; + max-width: fit-content; } } } From f02304e2f347798c28c67330cfe77e778ae643a3 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 8 Nov 2021 16:43:23 +0200 Subject: [PATCH 236/303] Add max fields length validation --- .../java/org/thingsboard/server/common/data/ContactBased.java | 1 + .../java/org/thingsboard/server/common/data/DashboardInfo.java | 1 + .../java/org/thingsboard/server/common/data/DeviceProfile.java | 1 + .../server/common/data/widget/WidgetTypeDetails.java | 2 +- .../thingsboard/server/common/data/widget/WidgetsBundle.java | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java b/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java index 4a57a84b1c..bcbce04898 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java @@ -44,6 +44,7 @@ public abstract class ContactBased extends SearchTextBasedW @Length(fieldName = "phone") @NoXss protected String phone; + @Length(fieldName = "email") @NoXss protected String email; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java index 4463ef9657..ddf7bbac36 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java @@ -35,6 +35,7 @@ public class DashboardInfo extends SearchTextBased implements HasNa @NoXss @Length(fieldName = "title") private String title; + @Length(fieldName = "image", max = 1000000) private String image; @Valid private Set assignedCustomers; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 4c5a2183cb..8a815547d6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -54,6 +54,7 @@ public class DeviceProfile extends SearchTextBased implements H @NoXss @ApiModelProperty(position = 11, value = "Device Profile description. ") private String description; + @Length(fieldName = "image", max = 1000000) @ApiModelProperty(position = 12, value = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ") private String image; private boolean isDefault; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java index 1af83de90d..8c3813d5c1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.validation.NoXss; @JsonPropertyOrder({ "alias", "name", "image", "description", "descriptor" }) public class WidgetTypeDetails extends WidgetType { - @NoXss + @Length(fieldName = "image", max = 1000000) @ApiModelProperty(position = 8, value = "Base64 encoded thumbnail", readOnly = true) private String image; @NoXss diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java index 2d04f3d4ef..d0df03702e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java @@ -50,6 +50,7 @@ public class WidgetsBundle extends SearchTextBased implements H @ApiModelProperty(position = 5, value = "Title used in search and UI", readOnly = true) private String title; + @Length(fieldName = "image", max = 1000000) @Getter @Setter @ApiModelProperty(position = 6, value = "Base64 encoded thumbnail", readOnly = true) From c621d41b1b833cb618eb2a679e8da91a203b9b35 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 8 Nov 2021 14:52:48 +0200 Subject: [PATCH 237/303] version upgrade: cache cleanup service added to clear caches that can not deserialize anymore due to schema upgrade --- .../install/ThingsboardInstallService.java | 9 +++ .../install/update/CacheCleanupService.java | 22 ++++++ .../update/DefaultCacheCleanupService.java | 75 +++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 application/src/main/java/org/thingsboard/server/service/install/update/CacheCleanupService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java 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 d66810093f..ccdac8b363 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -31,6 +31,7 @@ import org.thingsboard.server.service.install.TsDatabaseSchemaService; import org.thingsboard.server.service.install.TsLatestDatabaseSchemaService; import org.thingsboard.server.service.install.migrate.EntitiesMigrateService; import org.thingsboard.server.service.install.migrate.TsLatestMigrateService; +import org.thingsboard.server.service.install.update.CacheCleanupService; import org.thingsboard.server.service.install.update.DataUpdateService; @Service @@ -74,6 +75,9 @@ public class ThingsboardInstallService { @Autowired private DataUpdateService dataUpdateService; + @Autowired + private CacheCleanupService cacheCleanupService; + @Autowired(required = false) private EntitiesMigrateService entitiesMigrateService; @@ -85,6 +89,8 @@ public class ThingsboardInstallService { if (isUpgrade) { log.info("Starting ThingsBoard Upgrade from version {} ...", upgradeFromVersion); + cacheCleanupService.clearCache(upgradeFromVersion); + if ("2.5.0-cassandra".equals(upgradeFromVersion)) { log.info("Migrating ThingsBoard entities data from cassandra to SQL database ..."); entitiesMigrateService.migrate(); @@ -207,6 +213,9 @@ public class ThingsboardInstallService { log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; + + //TODO update CacheCleanupService on the next version upgrade + default: throw new RuntimeException("Unable to upgrade ThingsBoard, unsupported fromVersion: " + upgradeFromVersion); diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/CacheCleanupService.java b/application/src/main/java/org/thingsboard/server/service/install/update/CacheCleanupService.java new file mode 100644 index 0000000000..14a8bddc67 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/update/CacheCleanupService.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2021 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.install.update; + +public interface CacheCleanupService { + + void clearCache(String fromVersion) throws Exception; + +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java new file mode 100644 index 0000000000..3e5a5658f7 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java @@ -0,0 +1,75 @@ +/** + * Copyright © 2016-2021 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.install.update; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +@Service +@Profile("install") +@Slf4j +public class DefaultCacheCleanupService implements CacheCleanupService { + + @Autowired + CacheManager cacheManager; + + /** + * Cleanup caches that can not deserialize anymore due to schema upgrade or data update using sql scripts. + * Refer to SqlDatabaseUpgradeService and /data/upgrage/*.sql + * to discover which tables were changed + * */ + @Override + public void clearCache(String fromVersion) throws Exception { + switch (fromVersion) { + case "3.0.1": + log.info("Clear cache to upgrade from version 3.0.1 to 3.1.0 ..."); + clearAllCaches(); + //do not break to show explicit calls for next versions + case "3.1.1": + log.info("Clear cache to upgrade from version 3.1.1 to 3.2.0 ..."); + clearCacheByName("devices"); + clearCacheByName("deviceProfiles"); + clearCacheByName("tenantProfiles"); + case "3.2.2": + log.info("Clear cache to upgrade from version 3.2.2 to 3.3.0 ..."); + clearCacheByName("devices"); + clearCacheByName("deviceProfiles"); + clearCacheByName("tenantProfiles"); + clearCacheByName("relations"); + + break; + default: + throw new RuntimeException("Unable to update cache, unsupported fromVersion: " + fromVersion); + } + } + + void clearAllCaches() { + cacheManager.getCacheNames().forEach(this::clearCacheByName); + } + + void clearCacheByName(final String cacheName) { + Cache cache = cacheManager.getCache(cacheName); + Objects.requireNonNull(cache, "Cache does not exist for name " + cacheName); + cache.clear(); + } + +} From b5da59e3b38e230ac50639020ab2c96b54cac5fa Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 28 Sep 2021 23:26:50 +0300 Subject: [PATCH 238/303] fixed double sending rpc (private network) --- .../server/transport/lwm2m/server/client/LwM2mClient.java | 4 ++++ .../lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java | 3 +++ .../lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java | 2 ++ 3 files changed, 9 insertions(+) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index ff587f50c5..446f447623 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -117,6 +117,10 @@ public class LwM2mClient implements Serializable { @Getter private final AtomicInteger retryAttempts; + @Getter + @Setter + private Integer lastSentRpcId; + public Object clone() throws CloneNotSupportedException { return super.clone(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index bdc5dcc819..5fcc8a6826 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -95,6 +95,9 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); return; } + if (client.getLastSentRpcId() != null && client.getLastSentRpcId().equals(rpcRequest.getRequestId())) { + log.info("[{}] Rpc has already sent!", rpcRequest.getRequestId()); + } try { if (operationType.isHasObjectId()) { String objectId = getIdFromParameters(client, rpcRequest); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java index 5361682491..dbc0b020e5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java @@ -45,6 +45,7 @@ public abstract class RpcDownlinkRequestCallbackProxy implements DownlinkR @Override public void onSent(R request) { + client.setLastSentRpcId(this.request.getRequestId()); transportService.process(client.getSession(), this.request, RpcStatus.SENT, TransportServiceCallback.EMPTY); } @@ -68,6 +69,7 @@ public abstract class RpcDownlinkRequestCallbackProxy implements DownlinkR @Override public void onError(String params, Exception e) { if (e instanceof TimeoutException || e instanceof org.eclipse.leshan.core.request.exception.TimeoutException) { + client.setLastSentRpcId(null); transportService.process(client.getSession(), this.request, RpcStatus.TIMEOUT, TransportServiceCallback.EMPTY); } else if (!(e instanceof ClientSleepingException)) { sendRpcReplyOnError(e); From 183f3547a361c9cff0ef365cfd20da37ea5f3de3 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 29 Sep 2021 13:12:04 +0300 Subject: [PATCH 239/303] added lock for onSent rpc --- .../lwm2m/server/client/LwM2mClient.java | 2 +- .../DefaultLwM2mDownlinkMsgHandler.java | 5 ++++- .../downlink/DownlinkRequestCallback.java | 4 +++- .../rpc/DefaultLwM2MRpcRequestHandler.java | 7 +++++-- .../rpc/RpcDownlinkRequestCallbackProxy.java | 18 ++++++++++++++++-- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 446f447623..9534be8516 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -119,7 +119,7 @@ public class LwM2mClient implements Serializable { @Getter @Setter - private Integer lastSentRpcId; + private UUID lastSentRpcId; public Object clone() throws CloneNotSupportedException { return super.clone(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 681ae6e8f0..df761c3be5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -319,6 +319,10 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im Registration registration = client.getRegistration(); try { logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), pathToStringFunction.apply(request))); + if (!callback.onSent(request)) { + return; + } + context.getServer().send(registration, request, timeoutInMs, response -> { executor.submit(() -> { try { @@ -330,7 +334,6 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } }); }, e -> handleDownlinkError(client, request, callback, e)); - callback.onSent(request); } catch (Exception e) { handleDownlinkError(client, request, callback, e); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java index 2dc99479c1..8912c51960 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java @@ -17,7 +17,9 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; public interface DownlinkRequestCallback { - default void onSent(R request){}; + default boolean onSent(R request){ + return true; + }; void onSuccess(R request, T response); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 5fcc8a6826..118961850c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -95,8 +95,11 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); return; } - if (client.getLastSentRpcId() != null && client.getLastSentRpcId().equals(rpcRequest.getRequestId())) { - log.info("[{}] Rpc has already sent!", rpcRequest.getRequestId()); + UUID rpcId = new UUID(rpcRequest.getRequestIdMSB(), rpcRequest.getRequestIdLSB()); + + if (rpcId.equals(client.getLastSentRpcId())) { + log.debug("[{}]][{}] Rpc has already sent!", client.getEndpoint(), rpcId); + return; } try { if (operationType.isHasObjectId()) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java index dbc0b020e5..6221a68149 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.rpc; +import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.request.exception.ClientSleepingException; import org.thingsboard.common.util.JacksonUtil; @@ -26,8 +27,10 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; +import java.util.UUID; import java.util.concurrent.TimeoutException; +@Slf4j public abstract class RpcDownlinkRequestCallbackProxy implements DownlinkRequestCallback { private final TransportService transportService; @@ -44,9 +47,20 @@ public abstract class RpcDownlinkRequestCallbackProxy implements DownlinkR } @Override - public void onSent(R request) { - client.setLastSentRpcId(this.request.getRequestId()); + public boolean onSent(R request) { + client.lock(); + try { + UUID rpcId = new UUID(this.request.getRequestIdMSB(), this.request.getRequestIdLSB()); + if (rpcId.equals(client.getLastSentRpcId())) { + log.debug("[{}]][{}] Rpc has already sent!", client.getEndpoint(), rpcId); + return false; + } + client.setLastSentRpcId(rpcId); + } finally { + client.unlock(); + } transportService.process(client.getSession(), this.request, RpcStatus.SENT, TransportServiceCallback.EMPTY); + return true; } @Override From 24aa6f30ab738bd95511e85b47e153cb0bab8f2c Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 2 Nov 2021 19:26:25 +0200 Subject: [PATCH 240/303] fixed updating firstEdrxDownlink after error --- .../lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index df761c3be5..2ec0122c28 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -369,6 +369,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im private , T extends LwM2mResponse> void handleDownlinkError(LwM2mClient client, R request, DownlinkRequestCallback callback, Exception e) { log.trace("[{}] Received downlink error: {}.", client.getEndpoint(), e); + client.updateLastUplinkTime(); executor.submit(() -> { if (e instanceof TimeoutException || e instanceof ClientSleepingException) { log.trace("[{}] Received {}, client is probably sleeping", client.getEndpoint(), e.getClass().getSimpleName()); From 3e39791ed06e38a969938f9fbb5cb7d525985c53 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 9 Nov 2021 15:27:14 +0200 Subject: [PATCH 241/303] Fix UUID wiki url --- .../org/thingsboard/server/controller/ControllerConstants.java | 2 +- .../org/thingsboard/server/controller/CustomerController.java | 3 ++- .../org/thingsboard/server/controller/DashboardController.java | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index 8c31f41964..c2f965beba 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -18,7 +18,7 @@ package org.thingsboard.server.controller; public class ControllerConstants { protected static final String NEW_LINE = "\n\n"; - protected static final String UUID_WIKI_LINK = "[time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address%29) "; + protected static final String UUID_WIKI_LINK = "[time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)). "; protected static final int DEFAULT_PAGE_SIZE = 1000; protected static final String ENTITY_TYPE = "entityType"; protected static final String CUSTOMER_ID = "customerId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index 7611d2da25..f8f3a605a8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -60,6 +60,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -136,7 +137,7 @@ public class CustomerController extends BaseController { } @ApiOperation(value = "Create or update Customer (saveCustomer)", - notes = "Creates or Updates the Customer. When creating customer, platform generates Customer Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address) " + + notes = "Creates or Updates the Customer. When creating customer, platform generates Customer Id as " + UUID_WIKI_LINK + "The newly created Customer Id will be present in the response. " + "Specify existing Customer Id to update the Customer. " + "Referencing non-existing Customer Id will cause 'Not Found' error." + TENANT_AUTHORITY_PARAGRAPH) diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index c10234042a..1d3265053d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -86,6 +86,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHO import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID; import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -166,7 +167,7 @@ public class DashboardController extends BaseController { } @ApiOperation(value = "Create Or Update Dashboard (saveDashboard)", - notes = "Create or update the Dashboard. When creating dashboard, platform generates Dashboard Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)." + + notes = "Create or update the Dashboard. When creating dashboard, platform generates Dashboard Id as " + UUID_WIKI_LINK + "The newly created Dashboard id will be present in the response. " + "Specify existing Dashboard id to update the dashboard. " + "Referencing non-existing dashboard Id will cause 'Not Found' error. " + From 7801c3d7aa27046129190f4537118e71dce41ba5 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Tue, 9 Nov 2021 15:49:26 +0200 Subject: [PATCH 242/303] Fix up fields length validation for rule nodes and alarm rules --- .../server/common/data/device/profile/DeviceProfileAlarm.java | 2 ++ .../thingsboard/server/common/data/rule/RuleChainMetaData.java | 2 ++ .../org/thingsboard/server/dao/rule/BaseRuleChainService.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java index 806925f244..ac77d5afc0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java @@ -19,6 +19,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; import javax.validation.Valid; @@ -32,6 +33,7 @@ public class DeviceProfileAlarm implements Serializable { @ApiModelProperty(position = 1, value = "String value representing the alarm rule id", example = "highTemperatureAlarmID") private String id; + @Length(fieldName = "alarm type") @NoXss @ApiModelProperty(position = 2, value = "String value representing type of the alarm", example = "High Temperature Alarm") private String alarmType; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java index 0b069d7889..00b64ba9a9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java @@ -21,6 +21,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.id.RuleChainId; +import javax.validation.Valid; import java.util.ArrayList; import java.util.List; @@ -37,6 +38,7 @@ public class RuleChainMetaData { @ApiModelProperty(position = 2, required = true, value = "Index of the first rule node in the 'nodes' list") private Integer firstNodeIndex; + @Valid @ApiModelProperty(position = 3, required = true, value = "List of rule node JSON objects") private List nodes; diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 99772ddabd..32dbe39502 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -52,6 +52,7 @@ import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.service.ConstraintValidator; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; @@ -135,6 +136,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (ruleChain == null) { return false; } + ConstraintValidator.validateFields(ruleChainMetaData); if (CollectionUtils.isNotEmpty(ruleChainMetaData.getConnections())) { validateCircles(ruleChainMetaData.getConnections()); From 04b0bc4c81a5b6701d2111da4975cbd54d2ae8de Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 9 Nov 2021 16:37:21 +0200 Subject: [PATCH 243/303] UI: Fixed fields length validation for rule nodes and alarm rules --- .../profile/alarm/device-profile-alarm.component.html | 3 +++ .../components/profile/alarm/device-profile-alarm.component.ts | 2 +- .../home/pages/rulechain/rule-node-details.component.html | 3 +++ .../home/pages/rulechain/rule-node-details.component.ts | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 ++ 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html index a332cda0bf..ab151f6d93 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html @@ -45,6 +45,9 @@ {{ 'device-profile.alarm-type-unique' | translate }} + + {{ 'device-profile.alarm-type-max-length' | translate }} + diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts index a77641505b..20ea89e53c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts @@ -93,7 +93,7 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit ngOnInit() { this.alarmFormGroup = this.fb.group({ id: [null, Validators.required], - alarmType: [null, Validators.required], + alarmType: [null, [Validators.required, Validators.maxLength(255)]], createRules: [null], clearRule: [null], propagate: [null], diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html index 97d03a8d73..451b8ad8ee 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html @@ -32,6 +32,9 @@ || ruleNodeFormGroup.get('name').hasError('pattern')"> {{ 'rulenode.name-required' | translate }} + + {{ 'rulenode.name-max-length' | translate }} + {{ 'rulenode.debug-mode' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts index d5a3fcc8a0..4627b2a06b 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts @@ -78,7 +78,7 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) { this.ruleNodeFormGroup = this.fb.group({ - name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], + name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*'), Validators.maxLength(255)]], debugMode: [this.ruleNode.debugMode, []], configuration: [this.ruleNode.configuration, [Validators.required]], additionalInfo: this.fb.group( diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 8b7ff34a54..bd14f73e27 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1169,6 +1169,7 @@ "alarm-type": "Alarm type", "alarm-type-required": "Alarm type is required.", "alarm-type-unique": "Alarm type must be unique within the device profile alarm rules.", + "alarm-type-max-length": "Alarm type should be less than 256", "create-alarm-pattern": "Create {{alarmType}} alarm", "create-alarm-rules": "Create alarm rules", "no-create-alarm-rules": "No create conditions configured", @@ -2578,6 +2579,7 @@ "add": "Add rule node", "name": "Name", "name-required": "Name is required.", + "name-max-length": "Name should be less than 256", "type": "Type", "description": "Description", "delete": "Delete rule node", From 1fa4aff5dc8373a17857e50d0a5dba81fe648b53 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 9 Nov 2021 16:42:45 +0200 Subject: [PATCH 244/303] Bug fix in Cache Cleanup Service --- .../install/update/DefaultCacheCleanupService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java index 3e5a5658f7..bcfd287e66 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.install.update; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; @@ -24,13 +25,13 @@ import org.springframework.stereotype.Service; import java.util.Objects; +@RequiredArgsConstructor @Service @Profile("install") @Slf4j public class DefaultCacheCleanupService implements CacheCleanupService { - @Autowired - CacheManager cacheManager; + private final CacheManager cacheManager; /** * Cleanup caches that can not deserialize anymore due to schema upgrade or data update using sql scripts. @@ -43,7 +44,7 @@ public class DefaultCacheCleanupService implements CacheCleanupService { case "3.0.1": log.info("Clear cache to upgrade from version 3.0.1 to 3.1.0 ..."); clearAllCaches(); - //do not break to show explicit calls for next versions + break; case "3.1.1": log.info("Clear cache to upgrade from version 3.1.1 to 3.2.0 ..."); clearCacheByName("devices"); @@ -55,10 +56,9 @@ public class DefaultCacheCleanupService implements CacheCleanupService { clearCacheByName("deviceProfiles"); clearCacheByName("tenantProfiles"); clearCacheByName("relations"); - break; default: - throw new RuntimeException("Unable to update cache, unsupported fromVersion: " + fromVersion); + //Do nothing, since cache cleanup is optional. } } From 540ccd0cd414baeab2b6253eb8831ec5c3fd6244 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 9 Nov 2021 17:25:14 +0200 Subject: [PATCH 245/303] upgrade: clear cache - //do not break to show explicit calls for next versions --- .../service/install/update/DefaultCacheCleanupService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java index bcfd287e66..1456b3f975 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java @@ -44,7 +44,7 @@ public class DefaultCacheCleanupService implements CacheCleanupService { case "3.0.1": log.info("Clear cache to upgrade from version 3.0.1 to 3.1.0 ..."); clearAllCaches(); - break; + //do not break to show explicit calls for next versions case "3.1.1": log.info("Clear cache to upgrade from version 3.1.1 to 3.2.0 ..."); clearCacheByName("devices"); From ec84c9cf5159bbcca00beacb5488a6da3788a87f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 10 Nov 2021 13:02:15 +0200 Subject: [PATCH 246/303] UI: Fixed json attribute widget - showed two errors at the same time. --- .../lib/json-input-widget.component.html | 17 ++----- .../lib/json-input-widget.component.scss | 1 - .../widget/lib/json-input-widget.component.ts | 44 ++++++++----------- 3 files changed, 23 insertions(+), 39 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html index 81c06fe0f7..3c9cc99eca 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html @@ -22,7 +22,7 @@ class="tb-json-input__form" [formGroup]="attributeUpdateFormGroup" (ngSubmit)="save()"> -
        +
        -
        -
        - {{ 'widgets.input-widgets.no-entity-selected' | translate }} -
        -
        - {{ 'widgets.input-widgets.no-datakey-selected' | translate }} -
        -
        + +
        {{ errorMessage | translate }}
        -
        +
        diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.scss index f097de5afb..217c91dc4a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.scss @@ -25,7 +25,6 @@ } &__error { - text-align: center; font-size: 18px; color: #a0a0a0; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts index ce174fcde0..9fcf4c13bd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts @@ -28,7 +28,7 @@ import { AttributeService } from '@core/http/attribute.service'; import { AttributeData, AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; import { EntityId } from '@shared/models/id/entity-id'; import { EntityType } from '@shared/models/entity-type.models'; -import { createLabelFromDatasource } from '@core/utils'; +import { createLabelFromDatasource, isDefinedAndNotNull } from '@core/utils'; import { Observable } from 'rxjs'; enum JsonInputWidgetMode { @@ -63,9 +63,7 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit { labelValue: string; - entityDetected = false; - dataKeyDetected = false; - isValidParameter = false; + datasourceDetected = false; errorMessage: string; isFocused: boolean; @@ -111,30 +109,26 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit { } private validateDatasources() { - if (this.datasource?.type === DatasourceType.entity) { - this.entityDetected = true; - if (this.datasource.dataKeys.length) { - this.dataKeyDetected = true; - - if (this.settings.widgetMode === JsonInputWidgetMode.ATTRIBUTE) { - if (this.datasource.dataKeys[0].type === DataKeyType.attribute) { - if (this.settings.attributeScope === AttributeScope.SERVER_SCOPE || this.datasource.entityType === EntityType.DEVICE) { - this.isValidParameter = true; - } else { - this.errorMessage = 'widgets.input-widgets.not-allowed-entity'; - } - } else { - this.errorMessage = 'widgets.input-widgets.no-attribute-selected'; + this.datasourceDetected = isDefinedAndNotNull(this.datasource); + if (!this.datasourceDetected) { + return; + } + if (this.datasource.type === DatasourceType.entity) { + if (this.settings.widgetMode === JsonInputWidgetMode.ATTRIBUTE) { + if (this.datasource.dataKeys[0].type === DataKeyType.attribute) { + if (this.settings.attributeScope !== AttributeScope.SERVER_SCOPE && this.datasource.entityType !== EntityType.DEVICE) { + this.errorMessage = 'widgets.input-widgets.not-allowed-entity'; } } else { - if (this.datasource.dataKeys[0].type === DataKeyType.timeseries) { - this.isValidParameter = true; - } else { - this.errorMessage = 'widgets.input-widgets.no-timeseries-selected'; - } + this.errorMessage = 'widgets.input-widgets.no-attribute-selected'; + } + } else { + if (this.datasource.dataKeys[0].type !== DataKeyType.timeseries) { + this.errorMessage = 'widgets.input-widgets.no-timeseries-selected'; } - } + } else { + this.errorMessage = 'widgets.input-widgets.no-entity-selected'; } } @@ -152,7 +146,7 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit { } private updateWidgetData(data: Array) { - if (this.isValidParameter) { + if (!this.errorMessage) { let value = {}; if (data[0].data[0][1] !== '') { try { From 5ffeb80f8d44a7eabcdfb4180c383a37dbcfde33 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 10 Nov 2021 15:32:01 +0200 Subject: [PATCH 247/303] UI: Improvement api usage page, incorrect display long button text --- .../home/pages/api-usage/api_usage_json.raw | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw b/ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw index 44b0b04b02..19351e4de3 100644 --- a/ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw +++ b/ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw @@ -1,6 +1,8 @@ { "title": "Api Usage", "image": null, + "mobileHide": false, + "mobileOrder": null, "configuration": { "description": "", "widgets": { @@ -125,7 +127,7 @@ "padding": "0", "settings": { "cardHtml": "
        \n \n \n
        \n
        \n
        \n
        ${title}
        \n
        ${apiState}
        \n
        \n
        \n
        ${unit}
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n \n
        \n
        ", - "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-button {\n text-transform: uppercase;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n" + "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-button {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n" }, "title": "JavaScript functions", "dropShadow": true, @@ -283,7 +285,7 @@ "padding": "0", "settings": { "cardHtml": "
        \n \n \n
        \n
        \n
        \n
        ${title}
        \n
        ${apiState}
        \n
        \n
        \n
        ${unit}
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n \n
        \n
        ", - "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-button {\n text-transform: uppercase;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n" + "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-button {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n" }, "title": "Telemetry persistence", "dropShadow": true, @@ -440,7 +442,7 @@ "color": "#666666", "padding": "0", "settings": { - "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-button {\n text-transform: uppercase;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n", + "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-button {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n", "cardHtml": "
        \n \n \n
        \n
        \n
        \n
        ${title}
        \n
        ${apiState}
        \n
        \n
        \n
        ${unit}
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n \n \n
        \n
        " }, "title": "Rule Engine execution", @@ -622,7 +624,7 @@ "padding": "0", "settings": { "cardHtml": "
        \n \n \n
        \n
        \n
        \n
        \n ${title}\n
        \n
        ${apiState}
        \n
        \n
        \n
        \n
        \n
        {i18n:api-usage.messages}
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        {i18n:api-usage.data-points}
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n \n
        \n
        ", - "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bars-row {\n flex: 1;\n display: flex;\n flex-direction: row;\n}\n\n.card .bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n.card .mat-button {\n text-transform: uppercase;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 6px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n" + "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bars-row {\n flex: 1;\n display: flex;\n flex-direction: row;\n}\n\n.card .bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n.card .mat-button {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 6px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n" }, "title": "Transport", "dropShadow": true, @@ -780,7 +782,7 @@ "padding": "0", "settings": { "cardHtml": "
        \n \n \n
        \n
        \n
        \n
        ${title}
        \n
        ${apiState}
        \n
        \n
        \n
        ${unit}
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n \n
        \n
        ", - "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-button {\n text-transform: uppercase;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n" + "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-button {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n" }, "title": "Alarm created", "dropShadow": true, @@ -4054,7 +4056,7 @@ "color": "#666666", "padding": "0", "settings": { - "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bars-row {\n flex: 1;\n display: flex;\n flex-direction: row;\n}\n\n.card .bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n.card .mat-button {\n text-transform: uppercase;\n}\n\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 6px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n", + "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bars-row {\n flex: 1;\n display: flex;\n flex-direction: row;\n}\n\n.card .bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n.card .mat-button {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.card .mat-button-wrapper {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 6px;\n }\n .card .mat-button {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-button {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-button {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n", "cardHtml": "
        \n \n \n
        \n
        \n
        \n
        \n ${title}\n
        \n
        \n
        \n
        \n
        \n
        \n
        {i18n:api-usage.email}
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        {i18n:api-usage.sms}
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n \n
        \n
        " }, "title": "Notifications (Email/SMS)", From d7ed199ba8b52aaba06a25922adaf0b6479ccec1 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 10 Nov 2021 17:26:56 +0200 Subject: [PATCH 248/303] Websocket keep-alive / ping set to 15 seconds --- application/src/main/resources/thingsboard.yml | 18 ++++++++++-------- .../src/main/resources/tb-coap-transport.yml | 2 +- .../src/main/resources/tb-http-transport.yml | 2 +- .../src/main/resources/tb-lwm2m-transport.yml | 4 ++-- .../src/main/resources/tb-mqtt-transport.yml | 6 ++++-- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index ebf5501f4a..90b52c8b02 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -31,7 +31,7 @@ server: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${SSL_PEM_CERT:server.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${SSL_PEM_KEY:server_key.pem}" # Server certificate private key password (optional) key_password: "${SSL_PEM_KEY_PASSWORD:server_key_password}" @@ -54,7 +54,7 @@ server: log_controller_error_stack_trace: "${HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE:false}" ws: send_timeout: "${TB_SERVER_WS_SEND_TIMEOUT:5000}" - ping_timeout: "${TB_SERVER_WS_PING_TIMEOUT:30000}" + ping_timeout: "${TB_SERVER_WS_PING_TIMEOUT:15000}" limits: # Limit the amount of sessions and subscriptions available on each server. Put values to zero to disable particular limitation max_sessions_per_tenant: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_SESSIONS_PER_TENANT:0}" @@ -644,7 +644,7 @@ transport: bind_address: "${MQTT_SSL_BIND_ADDRESS:0.0.0.0}" # MQTT SSL bind port bind_port: "${MQTT_SSL_BIND_PORT:8883}" - # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext + # SSL protocol: See https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}" # Server SSL credentials credentials: @@ -654,7 +654,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}" # Server certificate private key password (optional) key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}" @@ -666,7 +666,9 @@ transport: store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" # Password used to access the key store store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" - # Password used to access the key + # Optional alias of the private key; If not set, the platform will load the first private key from the keystore; + key_alias: "${MQTT_SSL_KEY_ALIAS:}" + # Optional password to access the private key. If not set, the platform will attempt to load the private keys that are not protected with the password; key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" @@ -694,7 +696,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}" # Server certificate private key password (optional) key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}" @@ -736,7 +738,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}" # Server certificate private key password (optional) key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}" @@ -772,7 +774,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}" # Server certificate private key password (optional) key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}" diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 0caf66a36e..e6b373b787 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -106,7 +106,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}" # Server certificate private key password (optional) key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 17d86b0ea6..20f18ccfda 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -31,7 +31,7 @@ server: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${SSL_PEM_CERT:server.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${SSL_PEM_KEY:server_key.pem}" # Server certificate private key password (optional) key_password: "${SSL_PEM_KEY_PASSWORD:server_key_password}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index be51848337..8864b99e8c 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -121,7 +121,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}" # Server certificate private key password (optional) key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}" @@ -157,7 +157,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}" # Server certificate private key password (optional) key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 75538e6f61..435b780818 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -104,7 +104,7 @@ transport: bind_address: "${MQTT_SSL_BIND_ADDRESS:0.0.0.0}" # MQTT SSL bind port bind_port: "${MQTT_SSL_BIND_PORT:8883}" - # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext + # SSL protocol: See https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}" # Server SSL credentials credentials: @@ -114,7 +114,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}" - # Path to the server certificate private key file (optional) + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}" # Server certificate private key password (optional) key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}" @@ -126,6 +126,8 @@ transport: store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" # Password used to access the key store store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" + # Optional alias of the private key; If not set, the platform will load the first private key from the keystore; + key_alias: "${MQTT_SSL_KEY_ALIAS:}" # Password used to access the key key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" # Skip certificate validity check for client certificates. From 1c951c2e40a3dbe1adb0d0810cb5b776c2e34862 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 10 Nov 2021 16:46:15 +0200 Subject: [PATCH 249/303] Mqtt rule node remove default host --- .../thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java | 1 - 1 file changed, 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java index e06824180e..9ac797a98a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java @@ -37,7 +37,6 @@ public class TbMqttNodeConfiguration implements NodeConfiguration Date: Thu, 11 Nov 2021 09:44:53 +0200 Subject: [PATCH 250/303] Update rule nodes UI --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 cea69d4d4e..3505c30a5a 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 @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
        "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
        tb.rulenode.notify-device-hint
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
        \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
        \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
        \n
        \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
        \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
        tb.rulenode.create-entity-if-not-exists-hint
        \n
        \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
        tb.rulenode.remove-current-relations-hint
        \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
        tb.rulenode.change-originator-to-related-entity-hint
        \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
        \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-period-in-seconds-patterns-hint
        \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
        \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.delete-relation-hint
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
        \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
        \n \n \n \n
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
        \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
        \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
        \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
        \n
        \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
        \n
        \n
        \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
        \n
        \n \n
        \n \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-type
        \n \n \n
        device.device-types
        \n \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-filters
        \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-message-types-found\n
        \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
        \n
        \n
        \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
        \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
        {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
        \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
        \n
        \n
        \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
        \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
        \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
        \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
        tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
        \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
        \n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
        \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
        \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n
        \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
        \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
        \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
        \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
        \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
        \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
        \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
        \n
        \n
        \n
        \n
        \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
        \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
        \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
        \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
        tb.rulenode.check-all-keys-hint
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
        \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.check-relation-hint
        \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
        \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
        \n \n \n \n
        \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
        \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-alarm-status-matching\n
        \n
        \n
        \n
        \n
        \n \n
        \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
        \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-entity-details-matching\n
        \n
        \n
        \n
        \n
        \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
        tb.rulenode.add-to-metadata-hint
        \n
        \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
        \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
        \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
        \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.aggregationTypes=a.AggregationType,n.aggregations=Object.keys(a.AggregationType),n.aggregationTypesTranslations=a.aggregationTranslations,n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[i.Validators.required]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
        \n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
        \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-interval-patterns-hint
        \n
        \n
        \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
        \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
        \n
        \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
        \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
        \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
        \n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
        \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
        "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
        tb.rulenode.notify-device-hint
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
        \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
        \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
        \n
        \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
        \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
        tb.rulenode.create-entity-if-not-exists-hint
        \n
        \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
        tb.rulenode.remove-current-relations-hint
        \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
        tb.rulenode.change-originator-to-related-entity-hint
        \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
        \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-period-in-seconds-patterns-hint
        \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
        \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.delete-relation-hint
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
        \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
        \n \n \n \n
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
        \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
        \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
        \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
        \n
        \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
        \n
        \n
        \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
        \n
        \n \n
        \n \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-type
        \n \n \n
        device.device-types
        \n \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-filters
        \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-message-types-found\n
        \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
        \n
        \n
        \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
        \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
        {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
        \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
        \n
        \n
        \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
        \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
        \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
        \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
        tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
        \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
        \n \n tb.rulenode.client-id\n \n \n
        tb.rulenode.client-id-hint
        \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
        \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-webkit-fit-content;max-width:-moz-fit-content;max-width:fit-content}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
        \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
        \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n
        \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
        \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
        \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
        \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
        \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
        \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
        \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
        \n
        \n
        \n
        \n
        \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-webkit-fit-content;max-width:-moz-fit-content;max-width:fit-content}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
        \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
        \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
        \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
        tb.rulenode.check-all-keys-hint
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
        \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.check-relation-hint
        \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
        \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
        \n \n \n \n
        \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
        \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-alarm-status-matching\n
        \n
        \n
        \n
        \n
        \n \n
        \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
        \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-entity-details-matching\n
        \n
        \n
        \n
        \n
        \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
        tb.rulenode.add-to-metadata-hint
        \n
        \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
        \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
        \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
        \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.aggregationTypes=a.AggregationType,n.aggregations=Object.keys(a.AggregationType),n.aggregationTypesTranslations=a.aggregationTranslations,n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[i.Validators.required]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
        \n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
        \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-interval-patterns-hint
        \n
        \n
        \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
        \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
        \n
        \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
        \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
        \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
        \n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
        \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":"Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.Majority of the MQTT brokers will not allow multiple connections with the same client id. To connect to such brokers, your mqtt client id must be unique. When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From f2974532c607ea239aff63bf0885628496f13bd4 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 11 Nov 2021 14:05:27 +0200 Subject: [PATCH 251/303] K8S scripts moved to separate repository --- k8s/.env | 8 - k8s/README.md | 130 ----- k8s/basic/tb-node-cache-configmap.yml | 26 - k8s/basic/thirdparty.yml | 181 ------- k8s/common/cassandra.yml | 164 ------- k8s/common/database-setup.yml | 43 -- k8s/common/postgres.yml | 102 ---- k8s/common/tb-coap-transport-configmap.yml | 65 --- k8s/common/tb-http-transport-configmap.yml | 65 --- k8s/common/tb-mqtt-transport-configmap.yml | 65 --- k8s/common/tb-namespace.yml | 22 - k8s/common/tb-node-configmap.yml | 67 --- k8s/common/tb-node-hybrid-configmap.yml | 32 -- k8s/common/tb-node-postgres-configmap.yml | 30 -- k8s/common/tb-node.yml | 98 ---- k8s/common/thingsboard.yml | 451 ------------------ .../tb-node-cache-configmap.yml | 27 -- k8s/high-availability/thirdparty.yml | 301 ------------ k8s/k8s-delete-all.sh | 20 - k8s/k8s-delete-resources.sh | 25 - k8s/k8s-delete-thirdparty.sh | 23 - k8s/k8s-deploy-resources.sh | 30 -- k8s/k8s-deploy-thirdparty.sh | 45 -- k8s/k8s-install-tb.sh | 106 ---- k8s/k8s-upgrade-tb.sh | 43 -- 25 files changed, 2169 deletions(-) delete mode 100644 k8s/.env delete mode 100644 k8s/README.md delete mode 100644 k8s/basic/tb-node-cache-configmap.yml delete mode 100644 k8s/basic/thirdparty.yml delete mode 100644 k8s/common/cassandra.yml delete mode 100644 k8s/common/database-setup.yml delete mode 100644 k8s/common/postgres.yml delete mode 100644 k8s/common/tb-coap-transport-configmap.yml delete mode 100644 k8s/common/tb-http-transport-configmap.yml delete mode 100644 k8s/common/tb-mqtt-transport-configmap.yml delete mode 100644 k8s/common/tb-namespace.yml delete mode 100644 k8s/common/tb-node-configmap.yml delete mode 100644 k8s/common/tb-node-hybrid-configmap.yml delete mode 100644 k8s/common/tb-node-postgres-configmap.yml delete mode 100644 k8s/common/tb-node.yml delete mode 100644 k8s/common/thingsboard.yml delete mode 100644 k8s/high-availability/tb-node-cache-configmap.yml delete mode 100644 k8s/high-availability/thirdparty.yml delete mode 100755 k8s/k8s-delete-all.sh delete mode 100755 k8s/k8s-delete-resources.sh delete mode 100755 k8s/k8s-delete-thirdparty.sh delete mode 100755 k8s/k8s-deploy-resources.sh delete mode 100755 k8s/k8s-deploy-thirdparty.sh delete mode 100755 k8s/k8s-install-tb.sh delete mode 100755 k8s/k8s-upgrade-tb.sh diff --git a/k8s/.env b/k8s/.env deleted file mode 100644 index 4f0478683b..0000000000 --- a/k8s/.env +++ /dev/null @@ -1,8 +0,0 @@ -# Can be either basic (with single instance of Zookeeper, Kafka and Redis) or high-availability (with Zookeeper, Kafka and Redis in cluster modes). -# According to the deployment type corresponding kubernetes resources will be deployed (see content of the directories ./basic and ./high-availability for details). -DEPLOYMENT_TYPE=basic - -# Database used by ThingsBoard, can be either postgres (PostgreSQL) or hybrid (PostgreSQL for entities database and Cassandra for timeseries database). -# According to the database type corresponding kubernetes resources will be deployed (see postgres.yml, cassandra.yml for details). -DATABASE=postgres - diff --git a/k8s/README.md b/k8s/README.md deleted file mode 100644 index 9d91c8c0e8..0000000000 --- a/k8s/README.md +++ /dev/null @@ -1,130 +0,0 @@ -# Kubernetes resources configuration for ThingsBoard Microservices - -This folder containing scripts and Kubernetes resources configurations to run ThingsBoard in Microservices mode. - -## Prerequisites - -ThingsBoard Microservices run on the Kubernetes cluster. -You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. -If you do not have a cluster already, you can create one by using [Minikube](https://kubernetes.io/docs/setup/minikube), -or you can choose any other available [Kubernetes cluster deployment solutions](https://kubernetes.io/docs/setup/pick-right-solution/). - -### Enable ingress addon - -By default ingress addon is disabled in the Minikube, and available only in cluster providers. -To enable ingress, please execute the following command: - -` -$ minikube addons enable ingress -` - -## Installation - -Before performing initial installation you can configure the type of database to be used with ThingsBoard and the type of deployment. -To set database type change the value of `DATABASE` variable in `.env` file to one of the following: - -- `postgres` - use PostgreSQL database; -- `hybrid` - use PostgreSQL for entities database and Cassandra for timeseries database; - -**NOTE**: According to the database type corresponding kubernetes resources will be deployed (see `postgres.yml`, `cassandra.yml` for details). - -To set deployment type change the value of `DEPLOYMENT_TYPE` variable in `.env` file to one of the following: - -- `basic` - startup with a single instance of Zookeeper, Kafka and Redis; -- `high-availability` - startup with Zookeeper, Kafka, and Redis in cluster modes; - -**NOTE**: According to the deployment type corresponding kubernetes resources will be deployed (see the content of the directories `./basic` and `./high-availability` for details). - -Execute the following command to run the installation: - -` -$ ./k8s-install-tb.sh --loadDemo -` - -Where: - -- `--loadDemo` - optional argument. Whether to load additional demo data. - -## Running - -Execute the following command to deploy third-party resources: - -` -$ ./k8s-deploy-thirdparty.sh -` - -Type **'yes'** when prompted, if you are running ThingsBoard in `high-availability` `DEPLOYMENT_TYPE` for the first time and don't have configured Redis cluster. - -Execute the following command to deploy resources: - -` -$ ./k8s-deploy-resources.sh -` - -After a while when all resources will be successfully started you can open `http://{your-cluster-ip}` in your browser (for ex. `http://192.168.99.101`). -You should see the ThingsBoard login page. - -Use the following default credentials: - -- **System Administrator**: sysadmin@thingsboard.org / sysadmin - -If you installed DataBase with demo data (using `--loadDemo` flag) you can also use the following credentials: - -- **Tenant Administrator**: tenant@thingsboard.org / tenant -- **Customer User**: customer@thingsboard.org / customer - -In case of any issues, you can examine service logs for errors. -For example to see ThingsBoard node logs execute the following commands: - -1) Get the list of the running tb-node pods: - -` -$ kubectl get pods -l app=tb-node -` - -2) Fetch logs of the tb-node pod: - -` -$ kubectl logs -f [tb-node-pod-name] -` - -Where: - -- `tb-node-pod-name` - tb-node pod name obtained from the list of the running tb-node pods. - -Or use `kubectl get pods` to see the state of all the pods. -Or use `kubectl get services` to see the state of all the services. -Or use `kubectl get deployments` to see the state of all the deployments. -See [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) command reference for details. - -Execute the following command to delete all ThingsBoard microservices: - -` -$ ./k8s-delete-resources.sh -` - -Execute the following command to delete all third-party microservices: - -` -$ ./k8s-delete-thirdparty.sh -` - -Execute the following command to delete all resources (including database): - -` -$ ./k8s-delete-all.sh -` - -## Upgrading - -In case when database upgrade is needed, execute the following commands: - -``` -$ ./k8s-delete-resources.sh -$ ./k8s-upgrade-tb.sh --fromVersion=[FROM_VERSION] -$ ./k8s-deploy-resources.sh -``` - -Where: - -- `FROM_VERSION` - from which version upgrade should be started. See [Upgrade Instructions](https://thingsboard.io/docs/user-guide/install/upgrade-instructions) for valid `fromVersion` values. diff --git a/k8s/basic/tb-node-cache-configmap.yml b/k8s/basic/tb-node-cache-configmap.yml deleted file mode 100644 index 3a81044f0a..0000000000 --- a/k8s/basic/tb-node-cache-configmap.yml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-node-cache-config - namespace: thingsboard - labels: - name: tb-node-cache-config -data: - CACHE_TYPE: redis - REDIS_HOST: tb-redis \ No newline at end of file diff --git a/k8s/basic/thirdparty.yml b/k8s/basic/thirdparty.yml deleted file mode 100644 index edba32532e..0000000000 --- a/k8s/basic/thirdparty.yml +++ /dev/null @@ -1,181 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: zookeeper - namespace: thingsboard -spec: - selector: - matchLabels: - app: zookeeper - template: - metadata: - labels: - app: zookeeper - spec: - containers: - - name: server - imagePullPolicy: Always - image: zookeeper:3.5 - ports: - - containerPort: 2181 - readinessProbe: - periodSeconds: 5 - tcpSocket: - port: 2181 - livenessProbe: - initialDelaySeconds: 15 - periodSeconds: 5 - tcpSocket: - port: 2181 - env: - - name: ZOO_MY_ID - value: "1" - - name: ZOO_SERVERS - value: "server.1=0.0.0.0:2888:3888;0.0.0.0:2181" - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: zookeeper - namespace: thingsboard -spec: - type: ClusterIP - selector: - app: zookeeper - ports: - - name: zk-port - port: 2181 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-kafka - namespace: thingsboard -spec: - selector: - matchLabels: - app: tb-kafka - template: - metadata: - labels: - app: tb-kafka - spec: - containers: - - name: server - imagePullPolicy: Always - image: wurstmeister/kafka:2.12-2.2.1 - ports: - - containerPort: 9092 - readinessProbe: - periodSeconds: 20 - tcpSocket: - port: 9092 - livenessProbe: - initialDelaySeconds: 25 - periodSeconds: 5 - tcpSocket: - port: 9092 - env: - - name: KAFKA_ZOOKEEPER_CONNECT - value: "zookeeper:2181" - - name: KAFKA_LISTENERS - value: "INSIDE://:9093,OUTSIDE://:9092" - - name: KAFKA_ADVERTISED_LISTENERS - value: "INSIDE://:9093,OUTSIDE://tb-kafka:9092" - - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP - value: "INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT" - - name: KAFKA_INTER_BROKER_LISTENER_NAME - value: "INSIDE" - - name: KAFKA_CREATE_TOPICS - value: "js_eval.requests:100:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb_transport.api.requests:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb_rule_engine:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600" - - name: KAFKA_AUTO_CREATE_TOPICS_ENABLE - value: "false" - - name: KAFKA_LOG_RETENTION_BYTES - value: "1073741824" - - name: KAFKA_LOG_SEGMENT_BYTES - value: "268435456" - - name: KAFKA_LOG_RETENTION_MS - value: "300000" - - name: KAFKA_LOG_CLEANUP_POLICY - value: "delete" - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-kafka - namespace: thingsboard -spec: - type: ClusterIP - selector: - app: tb-kafka - ports: - - name: tb-kafka-port - port: 9092 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-redis - namespace: thingsboard -spec: - selector: - matchLabels: - app: tb-redis - template: - metadata: - labels: - app: tb-redis - spec: - containers: - - name: server - imagePullPolicy: Always - image: redis:4.0 - ports: - - containerPort: 6379 - readinessProbe: - periodSeconds: 5 - tcpSocket: - port: 6379 - livenessProbe: - periodSeconds: 5 - tcpSocket: - port: 6379 - volumeMounts: - - mountPath: /data - name: redis-data - volumes: - - name: redis-data - emptyDir: {} - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-redis - namespace: thingsboard -spec: - type: ClusterIP - selector: - app: tb-redis - ports: - - name: tb-redis-port - port: 6379 ---- \ No newline at end of file diff --git a/k8s/common/cassandra.yml b/k8s/common/cassandra.yml deleted file mode 100644 index 056851242d..0000000000 --- a/k8s/common/cassandra.yml +++ /dev/null @@ -1,164 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: fast - namespace: thingsboard -provisioner: k8s.io/minikube-hostpath -parameters: - type: pd-ssd ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: cassandra-probe-config - namespace: thingsboard - labels: - name: cassandra-probe-config -data: - probe: | - if [[ $(nodetool status | grep $POD_IP) == *"UN"* ]]; then - if [[ $DEBUG ]]; then - echo "UN"; - fi - exit 0; - else - if [[ $DEBUG ]]; then - echo "Not Up"; - fi - exit 1; - fi ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: cassandra - namespace: thingsboard - labels: - app: cassandra -spec: - serviceName: cassandra - replicas: 1 - selector: - matchLabels: - app: cassandra - template: - metadata: - labels: - app: cassandra - spec: - volumes: - - name: cassandra-probe-config - configMap: - name: cassandra-probe-config - items: - - key: probe - path: ready-probe.sh - mode: 0777 - terminationGracePeriodSeconds: 1800 - containers: - - name: cassandra - image: cassandra:3.11.3 - imagePullPolicy: Always - ports: - - containerPort: 7000 - name: intra-node - - containerPort: 7001 - name: tls-intra-node - - containerPort: 7199 - name: jmx - - containerPort: 9042 - name: cql - - containerPort: 9160 - name: thrift - resources: - limits: - cpu: "1000m" - memory: 2Gi - requests: - cpu: "1000m" - memory: 2Gi - securityContext: - capabilities: - add: - - IPC_LOCK - lifecycle: - preStop: - exec: - command: - - /bin/sh - - -c - - nodetool drain - env: - - name: CASSANDRA_SEEDS - value: "cassandra-0.cassandra.thingsboard.svc.cluster.local" - - name: MAX_HEAP_SIZE - value: 1024M - - name: HEAP_NEWSIZE - value: 256M - - name: CASSANDRA_CLUSTER_NAME - value: "Thingsboard Cluster" - - name: CASSANDRA_DC - value: "datacenter1" - - name: CASSANDRA_RACK - value: "Rack-Thingsboard-Cluster" - - name: CASSANDRA_AUTO_BOOTSTRAP - value: "false" - - name: CASSANDRA_ENDPOINT_SNITCH - value: GossipingPropertyFileSnitch - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - readinessProbe: - exec: - command: - - /bin/bash - - -c - - /probe/ready-probe.sh - initialDelaySeconds: 60 - timeoutSeconds: 5 - volumeMounts: - - name: cassandra-probe-config - mountPath: /probe - - name: cassandra-data - mountPath: /var/lib/cassandra - volumeClaimTemplates: - - metadata: - name: cassandra-data - spec: - accessModes: [ "ReadWriteOnce" ] - storageClassName: fast - resources: - requests: - storage: 1Gi ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: cassandra - name: cassandra - namespace: thingsboard -spec: - clusterIP: None - ports: - - port: 9042 - selector: - app: cassandra ---- diff --git a/k8s/common/database-setup.yml b/k8s/common/database-setup.yml deleted file mode 100644 index 1c7cd48a1b..0000000000 --- a/k8s/common/database-setup.yml +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: Pod -metadata: - name: tb-db-setup - namespace: thingsboard -spec: - volumes: - - name: tb-node-config - configMap: - name: tb-node-config - items: - - key: conf - path: thingsboard.conf - - key: logback - path: logback.xml - containers: - - name: tb-db-setup - imagePullPolicy: Always - image: thingsboard/tb-node:latest - envFrom: - - configMapRef: - name: tb-node-db-config - volumeMounts: - - mountPath: /config - name: tb-node-config - command: ['sh', '-c', 'while [ ! -f /tmp/install-finished ]; do sleep 2; done;'] - restartPolicy: Never diff --git a/k8s/common/postgres.yml b/k8s/common/postgres.yml deleted file mode 100644 index 40ed35d066..0000000000 --- a/k8s/common/postgres.yml +++ /dev/null @@ -1,102 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-pv-claim - namespace: thingsboard - labels: - app: postgres -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: postgres - namespace: thingsboard - labels: - app: postgres -spec: - selector: - matchLabels: - app: postgres - template: - metadata: - labels: - app: postgres - spec: - volumes: - - name: postgres-data - persistentVolumeClaim: - claimName: postgres-pv-claim - containers: - - name: postgres - imagePullPolicy: Always - image: postgres:12 - ports: - - containerPort: 5432 - name: postgres - env: - - name: POSTGRES_DB - value: "thingsboard" - - name: POSTGRES_PASSWORD - value: "postgres" - - name: PGDATA - value: /var/lib/postgresql/data/pgdata - volumeMounts: - - mountPath: /var/lib/postgresql/data - name: postgres-data - livenessProbe: - exec: - command: - - pg_isready - - -h - - localhost - - -U - - postgres - initialDelaySeconds: 60 - timeoutSeconds: 30 - readinessProbe: - exec: - command: - - pg_isready - - -h - - localhost - - -U - - postgres - initialDelaySeconds: 5 - timeoutSeconds: 1 - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-database - namespace: thingsboard -spec: - type: ClusterIP - selector: - app: postgres - ports: - - port: 5432 - name: postgres ---- diff --git a/k8s/common/tb-coap-transport-configmap.yml b/k8s/common/tb-coap-transport-configmap.yml deleted file mode 100644 index 0f0ea0a8e5..0000000000 --- a/k8s/common/tb-coap-transport-configmap.yml +++ /dev/null @@ -1,65 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-coap-transport-config - namespace: thingsboard - labels: - name: tb-coap-transport-config -data: - conf: | - export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/tb-coap-transport/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M" - export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-coap-transport/${TB_SERVICE_ID}-heapdump.bin" - export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" - export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10" - export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError" - export LOG_FILENAME=tb-coap-transport.out - export LOADER_PATH=/usr/share/tb-coap-transport/conf - logback: | - - - - - /var/log/tb-coap-transport/${TB_SERVICE_ID}/tb-coap-transport.log - - /var/log/tb-coap-transport/${TB_SERVICE_ID}/tb-coap-transport.%d{yyyy-MM-dd}.%i.log - 100MB - 30 - 3GB - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - diff --git a/k8s/common/tb-http-transport-configmap.yml b/k8s/common/tb-http-transport-configmap.yml deleted file mode 100644 index 582df2e5e8..0000000000 --- a/k8s/common/tb-http-transport-configmap.yml +++ /dev/null @@ -1,65 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-http-transport-config - namespace: thingsboard - labels: - name: tb-http-transport-config -data: - conf: | - export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/tb-http-transport/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M" - export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-http-transport/${TB_SERVICE_ID}-heapdump.bin" - export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" - export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10" - export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError" - export LOG_FILENAME=tb-http-transport.out - export LOADER_PATH=/usr/share/tb-http-transport/conf - logback: | - - - - - /var/log/tb-http-transport/${TB_SERVICE_ID}/tb-http-transport.log - - /var/log/tb-http-transport/${TB_SERVICE_ID}/tb-http-transport.%d{yyyy-MM-dd}.%i.log - 100MB - 30 - 3GB - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - diff --git a/k8s/common/tb-mqtt-transport-configmap.yml b/k8s/common/tb-mqtt-transport-configmap.yml deleted file mode 100644 index 0d82938842..0000000000 --- a/k8s/common/tb-mqtt-transport-configmap.yml +++ /dev/null @@ -1,65 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-mqtt-transport-config - namespace: thingsboard - labels: - name: tb-mqtt-transport-config -data: - conf: | - export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/tb-mqtt-transport/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M" - export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-mqtt-transport/${TB_SERVICE_ID}-heapdump.bin" - export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" - export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10" - export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError" - export LOG_FILENAME=tb-mqtt-transport.out - export LOADER_PATH=/usr/share/tb-mqtt-transport/conf - logback: | - - - - - /var/log/tb-mqtt-transport/${TB_SERVICE_ID}/tb-mqtt-transport.log - - /var/log/tb-mqtt-transport/${TB_SERVICE_ID}/tb-mqtt-transport.%d{yyyy-MM-dd}.%i.log - 100MB - 30 - 3GB - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - diff --git a/k8s/common/tb-namespace.yml b/k8s/common/tb-namespace.yml deleted file mode 100644 index c2056c7dd8..0000000000 --- a/k8s/common/tb-namespace.yml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: Namespace -metadata: - name: thingsboard - labels: - name: thingsboard diff --git a/k8s/common/tb-node-configmap.yml b/k8s/common/tb-node-configmap.yml deleted file mode 100644 index 3e796215ab..0000000000 --- a/k8s/common/tb-node-configmap.yml +++ /dev/null @@ -1,67 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-node-config - namespace: thingsboard - labels: - name: tb-node-config -data: - conf: | - export JAVA_OPTS="$JAVA_OPTS -Dplatform=deb -Dinstall.data_dir=/usr/share/thingsboard/data" - export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/thingsboard/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M" - export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/thingsboard/${TB_SERVICE_ID}-heapdump.bin" - export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" - export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10" - export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError" - export LOG_FILENAME=thingsboard.out - export LOADER_PATH=/usr/share/thingsboard/conf,/usr/share/thingsboard/extensions - logback: | - - - - - /var/log/thingsboard/${TB_SERVICE_ID}/thingsboard.log - - /var/log/thingsboard/${TB_SERVICE_ID}/thingsboard.%d{yyyy-MM-dd}.%i.log - 100MB - 30 - 3GB - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - - diff --git a/k8s/common/tb-node-hybrid-configmap.yml b/k8s/common/tb-node-hybrid-configmap.yml deleted file mode 100644 index 0ef6fc4dfb..0000000000 --- a/k8s/common/tb-node-hybrid-configmap.yml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-node-db-config - namespace: thingsboard - labels: - name: tb-node-db-config -data: - SPRING_JPA_DATABASE_PLATFORM: org.hibernate.dialect.PostgreSQLDialect - SPRING_DRIVER_CLASS_NAME: org.postgresql.Driver - SPRING_DATASOURCE_URL: jdbc:postgresql://tb-database:5432/thingsboard - SPRING_DATASOURCE_USERNAME: postgres - SPRING_DATASOURCE_PASSWORD: postgres - DATABASE_TS_TYPE: cassandra - CASSANDRA_URL: cassandra:9042 - CASSANDRA_SOCKET_READ_TIMEOUT: "60000" diff --git a/k8s/common/tb-node-postgres-configmap.yml b/k8s/common/tb-node-postgres-configmap.yml deleted file mode 100644 index 63cc0cb42c..0000000000 --- a/k8s/common/tb-node-postgres-configmap.yml +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-node-db-config - namespace: thingsboard - labels: - name: tb-node-db-config -data: - DATABASE_TS_TYPE: sql - SPRING_JPA_DATABASE_PLATFORM: org.hibernate.dialect.PostgreSQLDialect - SPRING_DRIVER_CLASS_NAME: org.postgresql.Driver - SPRING_DATASOURCE_URL: jdbc:postgresql://tb-database:5432/thingsboard - SPRING_DATASOURCE_USERNAME: postgres - SPRING_DATASOURCE_PASSWORD: postgres diff --git a/k8s/common/tb-node.yml b/k8s/common/tb-node.yml deleted file mode 100644 index 2520bf8e76..0000000000 --- a/k8s/common/tb-node.yml +++ /dev/null @@ -1,98 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-node - namespace: thingsboard -spec: - replicas: 2 - selector: - matchLabels: - app: tb-node - template: - metadata: - labels: - app: tb-node - spec: - volumes: - - name: tb-node-config - configMap: - name: tb-node-config - items: - - key: conf - path: thingsboard.conf - - key: logback - path: logback.xml - containers: - - name: server - imagePullPolicy: Always - image: thingsboard/tb-node:latest - ports: - - containerPort: 8080 - name: http - - containerPort: 9001 - name: rpc - env: - - name: TB_SERVICE_ID - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: TB_SERVICE_TYPE - value: "monolith" - - name: TB_QUEUE_TYPE - value: "kafka" - - name: ZOOKEEPER_ENABLED - value: "true" - - name: ZOOKEEPER_URL - value: "zookeeper:2181" - - name: TB_KAFKA_SERVERS - value: "tb-kafka:9092" - - name: JS_EVALUATOR - value: "remote" - - name: TRANSPORT_TYPE - value: "remote" - - name: HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE - value: "false" - envFrom: - - configMapRef: - name: tb-node-db-config - - configMapRef: - name: tb-node-cache-config - volumeMounts: - - mountPath: /config - name: tb-node-config - livenessProbe: - httpGet: - path: /login - port: http - initialDelaySeconds: 300 - timeoutSeconds: 10 - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-node - namespace: thingsboard -spec: - type: ClusterIP - selector: - app: tb-node - ports: - - port: 8080 - name: http \ No newline at end of file diff --git a/k8s/common/thingsboard.yml b/k8s/common/thingsboard.yml deleted file mode 100644 index 73b7133433..0000000000 --- a/k8s/common/thingsboard.yml +++ /dev/null @@ -1,451 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-js-executor - namespace: thingsboard -spec: - replicas: 20 - selector: - matchLabels: - app: tb-js-executor - template: - metadata: - labels: - app: tb-js-executor - spec: - containers: - - name: server - imagePullPolicy: Always - image: thingsboard/tb-js-executor:latest - env: - - name: REMOTE_JS_EVAL_REQUEST_TOPIC - value: "js_eval.requests" - - name: TB_KAFKA_SERVERS - value: "tb-kafka:9092" - - name: LOGGER_LEVEL - value: "info" - - name: LOG_FOLDER - value: "logs" - - name: LOGGER_FILENAME - value: "tb-js-executor-%DATE%.log" - - name: DOCKER_MODE - value: "true" - - name: SCRIPT_BODY_TRACE_FREQUENCY - value: "1000" - restartPolicy: Always ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-mqtt-transport - namespace: thingsboard -spec: - replicas: 2 - selector: - matchLabels: - app: tb-mqtt-transport - template: - metadata: - labels: - app: tb-mqtt-transport - spec: - volumes: - - name: tb-mqtt-transport-config - configMap: - name: tb-mqtt-transport-config - items: - - key: conf - path: tb-mqtt-transport.conf - - key: logback - path: logback.xml - containers: - - name: server - imagePullPolicy: Always - image: thingsboard/tb-mqtt-transport:latest - ports: - - containerPort: 1883 - name: mqtt - env: - - name: TB_SERVICE_ID - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: TB_QUEUE_TYPE - value: "kafka" - - name: MQTT_BIND_ADDRESS - value: "0.0.0.0" - - name: MQTT_BIND_PORT - value: "1883" - - name: MQTT_TIMEOUT - value: "10000" - - name: TB_KAFKA_SERVERS - value: "tb-kafka:9092" - volumeMounts: - - mountPath: /config - name: tb-mqtt-transport-config - readinessProbe: - periodSeconds: 20 - tcpSocket: - port: 1883 - livenessProbe: - initialDelaySeconds: 120 - periodSeconds: 20 - tcpSocket: - port: 1883 - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-mqtt-transport - namespace: thingsboard -spec: - type: LoadBalancer - selector: - app: tb-mqtt-transport - ports: - - port: 1883 - targetPort: 1883 - name: mqtt ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-http-transport - namespace: thingsboard -spec: - replicas: 2 - selector: - matchLabels: - app: tb-http-transport - template: - metadata: - labels: - app: tb-http-transport - spec: - volumes: - - name: tb-http-transport-config - configMap: - name: tb-http-transport-config - items: - - key: conf - path: tb-http-transport.conf - - key: logback - path: logback.xml - containers: - - name: server - imagePullPolicy: Always - image: thingsboard/tb-http-transport:latest - ports: - - containerPort: 8080 - name: http - env: - - name: TB_SERVICE_ID - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: TB_QUEUE_TYPE - value: "kafka" - - name: HTTP_BIND_ADDRESS - value: "0.0.0.0" - - name: HTTP_BIND_PORT - value: "8080" - - name: HTTP_REQUEST_TIMEOUT - value: "60000" - - name: TB_KAFKA_SERVERS - value: "tb-kafka:9092" - volumeMounts: - - mountPath: /config - name: tb-http-transport-config - readinessProbe: - periodSeconds: 20 - tcpSocket: - port: 8080 - livenessProbe: - initialDelaySeconds: 120 - periodSeconds: 20 - tcpSocket: - port: 8080 - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-http-transport - namespace: thingsboard -spec: - type: ClusterIP - selector: - app: tb-http-transport - ports: - - port: 8080 - name: http ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-coap-transport - namespace: thingsboard -spec: - replicas: 2 - selector: - matchLabels: - app: tb-coap-transport - template: - metadata: - labels: - app: tb-coap-transport - spec: - volumes: - - name: tb-coap-transport-config - configMap: - name: tb-coap-transport-config - items: - - key: conf - path: tb-coap-transport.conf - - key: logback - path: logback.xml - containers: - - name: server - imagePullPolicy: Always - image: thingsboard/tb-coap-transport:latest - ports: - - containerPort: 5683 - name: coap - protocol: UDP - env: - - name: TB_SERVICE_ID - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: TB_QUEUE_TYPE - value: "kafka" - - name: COAP_BIND_ADDRESS - value: "0.0.0.0" - - name: COAP_BIND_PORT - value: "5683" - - name: COAP_TIMEOUT - value: "10000" - - name: TB_KAFKA_SERVERS - value: "tb-kafka:9092" - volumeMounts: - - mountPath: /config - name: tb-coap-transport-config - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-coap-transport - namespace: thingsboard -spec: - type: LoadBalancer - selector: - app: tb-coap-transport - ports: - - port: 5683 - name: coap - protocol: UDP ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-lwm2m-transport - namespace: thingsboard -spec: - replicas: 2 - selector: - matchLabels: - app: tb-lwm2m-transport - template: - metadata: - labels: - app: tb-lwm2m-transport - spec: - volumes: - - name: tb-lwm2m-transport-config - configMap: - name: tb-lwm2m-transport-config - items: - - key: conf - path: tb-lwm2m-transport.conf - - key: logback - path: logback.xml - containers: - - name: server - imagePullPolicy: Always - image: thingsboard/tb-lwm2m-transport:latest - ports: - - containerPort: 5685 - name: lwm2m - protocol: UDP - env: - - name: TB_SERVICE_ID - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: TB_QUEUE_TYPE - value: "kafka" - - name: LWM2M_BIND_ADDRESS - value: "0.0.0.0" - - name: LWM2M_BIND_PORT - value: "5685" - - name: LWM2M_TIMEOUT - value: "10000" - - name: TB_KAFKA_SERVERS - value: "tb-kafka:9092" - volumeMounts: - - mountPath: /config - name: tb-lwm2m-transport-config - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-lwm2m-transport - namespace: thingsboard -spec: - type: LoadBalancer - selector: - app: tb-lwm2m-transport - ports: - - port: 5685 - name: lwm2m - protocol: UDP ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tb-web-ui - namespace: thingsboard -spec: - replicas: 2 - selector: - matchLabels: - app: tb-web-ui - template: - metadata: - labels: - app: tb-web-ui - spec: - containers: - - name: server - imagePullPolicy: Always - image: thingsboard/tb-web-ui:latest - ports: - - containerPort: 8080 - name: http - env: - - name: HTTP_BIND_ADDRESS - value: "0.0.0.0" - - name: HTTP_BIND_PORT - value: "8080" - - name: TB_ENABLE_PROXY - value: "false" - - name: LOGGER_LEVEL - value: "info" - - name: LOG_FOLDER - value: "logs" - - name: LOGGER_FILENAME - value: "tb-web-ui-%DATE%.log" - - name: DOCKER_MODE - value: "true" - livenessProbe: - httpGet: - path: /index.html - port: http - initialDelaySeconds: 120 - timeoutSeconds: 10 - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-web-ui - namespace: thingsboard -spec: - type: ClusterIP - selector: - app: tb-web-ui - ports: - - port: 8080 - name: http ---- -apiVersion: networking.k8s.io/v1beta1 -kind: Ingress -metadata: - name: tb-ingress - namespace: thingsboard - annotations: - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" -spec: - rules: - - http: - paths: - - path: /api/v1/.* - backend: - serviceName: tb-http-transport - servicePort: 8080 - - path: /api/.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: /swagger.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: /webjars.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: /v2/.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: /v3/.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: /static/rulenode/.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: /assets/help/.*/rulenode/.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: /oauth2/.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: /login/oauth2/.* - backend: - serviceName: tb-node - servicePort: 8080 - - path: / - backend: - serviceName: tb-web-ui - servicePort: 8080 - - path: /.* - backend: - serviceName: tb-web-ui - servicePort: 8080 ---- diff --git a/k8s/high-availability/tb-node-cache-configmap.yml b/k8s/high-availability/tb-node-cache-configmap.yml deleted file mode 100644 index 46800e4fe8..0000000000 --- a/k8s/high-availability/tb-node-cache-configmap.yml +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-node-cache-config - namespace: thingsboard - labels: - name: tb-node-cache-config -data: - CACHE_TYPE: redis - REDIS_CONNECTION_TYPE: cluster - REDIS_NODES: tb-redis:6379 \ No newline at end of file diff --git a/k8s/high-availability/thirdparty.yml b/k8s/high-availability/thirdparty.yml deleted file mode 100644 index 61f1fa73ce..0000000000 --- a/k8s/high-availability/thirdparty.yml +++ /dev/null @@ -1,301 +0,0 @@ -# -# Copyright © 2016-2021 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. -# - -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: zookeeper - namespace: thingsboard -spec: - serviceName: "zookeeper" - replicas: 3 - podManagementPolicy: Parallel - selector: - matchLabels: - app: zookeeper - template: - metadata: - labels: - app: zookeeper - spec: - containers: - - name: zookeeper - imagePullPolicy: Always - image: zookeeper:3.5 - ports: - - containerPort: 2181 - name: client - - containerPort: 2888 - name: server - - containerPort: 3888 - name: election - readinessProbe: - periodSeconds: 60 - tcpSocket: - port: 2181 - livenessProbe: - periodSeconds: 60 - tcpSocket: - port: 2181 - env: - - name: ZOO_SERVERS - value: "server.0=zookeeper-0.zookeeper:2888:3888;2181 server.1=zookeeper-1.zookeeper:2888:3888;2181 server.2=zookeeper-2.zookeeper:2888:3888;2181" - - name: JVMFLAGS - value: "-Dzookeeper.electionPortBindRetry=0" - volumeMounts: - - name: data - mountPath: /data - readOnly: false - initContainers: - - command: - - /bin/bash - - -c - - |- - set -ex; - mkdir -p "$ZOO_DATA_LOG_DIR" "$ZOO_DATA_DIR" "$ZOO_CONF_DIR"; - chown "$ZOO_USER:$ZOO_USER" "$ZOO_DATA_LOG_DIR" "$ZOO_DATA_DIR" "$ZOO_CONF_DIR" - if [[ ! -f "$ZOO_DATA_DIR/myid" ]]; then - echo $HOSTNAME| rev | cut -d "-" -f1 | rev > "$ZOO_DATA_DIR/myid" - fi - env: - - name: HOSTNAME - valueFrom: - fieldRef: - fieldPath: metadata.name - image: zookeeper:3.5 - imagePullPolicy: IfNotPresent - name: zookeeper-init - securityContext: - runAsUser: 0 - volumeMounts: - - name: data - mountPath: /data - readOnly: false - volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: [ "ReadWriteOnce" ] - resources: - requests: - storage: 100Mi ---- -apiVersion: v1 -kind: Service -metadata: - name: zookeeper - namespace: thingsboard -spec: - type: ClusterIP - ports: - - port: 2181 - targetPort: 2181 - name: client - - port: 2888 - targetPort: 2888 - name: server - - port: 3888 - targetPort: 3888 - name: election - selector: - app: zookeeper ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: tb-kafka - namespace: thingsboard -spec: - serviceName: "tb-kafka" - replicas: 3 - podManagementPolicy: Parallel - selector: - matchLabels: - app: tb-kafka - template: - metadata: - labels: - app: tb-kafka - spec: - containers: - - name: tb-kafka - imagePullPolicy: Always - image: wurstmeister/kafka:2.12-2.2.1 - ports: - - containerPort: 9092 - name: kafka-int - readinessProbe: - periodSeconds: 5 - timeoutSeconds: 5 - tcpSocket: - port: 9092 - initialDelaySeconds: 60 - livenessProbe: - timeoutSeconds: 5 - periodSeconds: 5 - tcpSocket: - port: 9092 - initialDelaySeconds: 80 - env: - - name: BROKER_ID_COMMAND - value: "hostname | cut -d'-' -f3" - - name: KAFKA_ZOOKEEPER_CONNECT - value: "zookeeper:2181" - - name: KAFKA_ZOOKEEPER_CONNECTION_TIMEOUT_MS - value: "60000" - - name: KAFKA_UNCLEAN_LEADER_ELECTION_ENABLE - value: "true" - - name: KAFKA_LISTENERS - value: "INSIDE://:9092" - - name: KAFKA_ADVERTISED_LISTENERS - value: "INSIDE://:9092" - - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP - value: "INSIDE:PLAINTEXT" - - name: KAFKA_INTER_BROKER_LISTENER_NAME - value: "INSIDE" - - name: KAFKA_CONTROLLER_SHUTDOWN_ENABLE - value: "true" - - name: KAFKA_CREATE_TOPICS - value: "js_eval.requests:100:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb_transport.api.requests:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb_rule_engine:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600" - - name: KAFKA_AUTO_CREATE_TOPICS_ENABLE - value: "false" - - name: KAFKA_LOG_RETENTION_BYTES - value: "1073741824" - - name: KAFKA_LOG_SEGMENT_BYTES - value: "268435456" - - name: KAFKA_LOG_RETENTION_MS - value: "300000" - - name: KAFKA_LOG_CLEANUP_POLICY - value: "delete" - - name: KAFKA_PORT - value: "9092" - - name: KAFKA_LOG_DIRS - value: "/kafka-logs" - volumeMounts: - - name: logs - mountPath: /kafka-logs - subPath: logs - volumeClaimTemplates: - - metadata: - name: logs - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-kafka - namespace: thingsboard -spec: - type: ClusterIP - ports: - - port: 9092 - targetPort: 9092 - name: kafka-int - selector: - app: tb-kafka ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: tb-redis - namespace: thingsboard -data: - update-node.sh: | - #!/bin/sh - REDIS_NODES="/data/nodes.conf" - sed -i -e "/myself/ s/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/${POD_IP}/" ${REDIS_NODES} - exec "$@" - redis.conf: |+ - cluster-enabled yes - cluster-require-full-coverage no - cluster-node-timeout 15000 - cluster-config-file /data/nodes.conf - cluster-migration-barrier 1 - appendonly yes - protected-mode no ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: tb-redis - namespace: thingsboard -spec: - serviceName: server - replicas: 6 - selector: - matchLabels: - app: tb-redis - template: - metadata: - labels: - app: tb-redis - spec: - containers: - - name: redis - image: redis:5.0.1-alpine - ports: - - containerPort: 6379 - name: client - - containerPort: 16379 - name: gossip - command: ["/conf/update-node.sh", "redis-server", "/conf/redis.conf"] - env: - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - volumeMounts: - - name: conf - mountPath: /conf - readOnly: false - - name: data - mountPath: /data - readOnly: false - volumes: - - name: conf - configMap: - name: tb-redis - defaultMode: 0755 - volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: [ "ReadWriteOnce" ] - resources: - requests: - storage: 100Mi ---- -apiVersion: v1 -kind: Service -metadata: - name: tb-redis - namespace: thingsboard -spec: - type: ClusterIP - ports: - - port: 6379 - targetPort: 6379 - name: client - - port: 16379 - targetPort: 16379 - name: gossip - selector: - app: tb-redis diff --git a/k8s/k8s-delete-all.sh b/k8s/k8s-delete-all.sh deleted file mode 100755 index 75dbd6fa60..0000000000 --- a/k8s/k8s-delete-all.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2021 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. -# - -kubectl -n thingsboard delete svc,sts,deploy,cm,po,ing --all - -kubectl -n thingsboard get pvc --no-headers=true | awk '//{print $1}' | xargs kubectl -n thingsboard delete --ignore-not-found=true pvc \ No newline at end of file diff --git a/k8s/k8s-delete-resources.sh b/k8s/k8s-delete-resources.sh deleted file mode 100755 index 3dea9a465d..0000000000 --- a/k8s/k8s-delete-resources.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2021 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. -# - -set -e - -source .env - -kubectl config set-context $(kubectl config current-context) --namespace=thingsboard - -kubectl delete -f common/thingsboard.yml -kubectl delete -f common/tb-node.yml diff --git a/k8s/k8s-delete-thirdparty.sh b/k8s/k8s-delete-thirdparty.sh deleted file mode 100755 index fc5fd3ce16..0000000000 --- a/k8s/k8s-delete-thirdparty.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2021 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. -# - -set -e - -source .env - -kubectl config set-context $(kubectl config current-context) --namespace=thingsboard -kubectl delete -f $DEPLOYMENT_TYPE/thirdparty.yml diff --git a/k8s/k8s-deploy-resources.sh b/k8s/k8s-deploy-resources.sh deleted file mode 100755 index 899b2e399d..0000000000 --- a/k8s/k8s-deploy-resources.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2021 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. -# - -set -e - -source .env - -kubectl apply -f common/tb-namespace.yml -kubectl config set-context $(kubectl config current-context) --namespace=thingsboard -kubectl apply -f common/tb-node-configmap.yml -kubectl apply -f common/tb-mqtt-transport-configmap.yml -kubectl apply -f common/tb-http-transport-configmap.yml -kubectl apply -f common/tb-coap-transport-configmap.yml -kubectl apply -f common/thingsboard.yml -kubectl apply -f $DEPLOYMENT_TYPE/tb-node-cache-configmap.yml -kubectl apply -f common/tb-node.yml diff --git a/k8s/k8s-deploy-thirdparty.sh b/k8s/k8s-deploy-thirdparty.sh deleted file mode 100755 index 6fd94c3674..0000000000 --- a/k8s/k8s-deploy-thirdparty.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2021 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. -# - -set -e - -source .env - -kubectl apply -f common/tb-namespace.yml -kubectl config set-context $(kubectl config current-context) --namespace=thingsboard - -kubectl apply -f $DEPLOYMENT_TYPE/thirdparty.yml - - -if [ "$DEPLOYMENT_TYPE" == "high-availability" ]; then - echo -n "waiting for all redis pods to be ready"; - while [[ $(kubectl get pods tb-redis-5 -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}' 2>/dev/null) != "True" ]]; - do - echo -n "." && sleep 5; - done - - if [[ $(kubectl exec -it tb-redis-0 -- redis-cli cluster info 2>&1 | head -n 1) =~ "cluster_state:ok" ]] - then - echo "redis cluster is already configured" - else - echo "starting redis cluster" - redisNodes=$(kubectl get pods -l app=tb-redis -o jsonpath='{range.items[*]}{.status.podIP}:6379 ') - kubectl exec -it tb-redis-0 -- redis-cli --cluster create --cluster-replicas 1 $redisNodes - fi - -fi - diff --git a/k8s/k8s-install-tb.sh b/k8s/k8s-install-tb.sh deleted file mode 100755 index 3dd714bac9..0000000000 --- a/k8s/k8s-install-tb.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2021 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. -# - -function installTb() { - - loadDemo=$1 - - kubectl apply -f common/tb-node-configmap.yml - kubectl apply -f common/database-setup.yml && - kubectl wait --for=condition=Ready pod/tb-db-setup --timeout=120s && - kubectl exec tb-db-setup -- sh -c 'export INSTALL_TB=true; export LOAD_DEMO='"$loadDemo"'; start-tb-node.sh; touch /tmp/install-finished;' - - kubectl delete pod tb-db-setup - -} - -function installPostgres() { - - kubectl apply -f common/postgres.yml - kubectl apply -f common/tb-node-postgres-configmap.yml - - kubectl rollout status deployment/postgres -} - -function installHybrid() { - - kubectl apply -f common/postgres.yml - kubectl apply -f common/cassandra.yml - kubectl apply -f common/tb-node-hybrid-configmap.yml - - kubectl rollout status deployment/postgres - kubectl rollout status statefulset/cassandra - - kubectl exec -it cassandra-0 -- bash -c "cqlsh -e \ - \"CREATE KEYSPACE IF NOT EXISTS thingsboard \ - WITH replication = { \ - 'class' : 'SimpleStrategy', \ - 'replication_factor' : 1 \ - };\"" -} - -while [[ $# -gt 0 ]] -do -key="$1" - -case $key in - --loadDemo) - LOAD_DEMO=true - shift # past argument - ;; - *) - # unknown option - ;; -esac -shift # past argument or value -done - -if [ "$LOAD_DEMO" == "true" ]; then - loadDemo=true -else - loadDemo=false -fi - -source .env - -kubectl apply -f common/tb-namespace.yml -kubectl config set-context $(kubectl config current-context) --namespace=thingsboard - -case $DEPLOYMENT_TYPE in - basic) - ;; - high-availability) - ;; - *) - echo "Unknown DEPLOYMENT_TYPE value specified: '${DEPLOYMENT_TYPE}'. Should be either basic or high-availability." >&2 - exit 1 -esac - -case $DATABASE in - postgres) - installPostgres - installTb ${loadDemo} - ;; - hybrid) - installHybrid - installTb ${loadDemo} - ;; - *) - echo "Unknown DATABASE value specified: '${DATABASE}'. Should be either postgres or hybrid." >&2 - exit 1 -esac - diff --git a/k8s/k8s-upgrade-tb.sh b/k8s/k8s-upgrade-tb.sh deleted file mode 100755 index 5e81e500a3..0000000000 --- a/k8s/k8s-upgrade-tb.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2021 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: k8s-upgrade-tb.sh --fromVersion={VERSION}" - exit 1 -else - fromVersion="${FROM_VERSION// }" -fi - -kubectl apply -f common/database-setup.yml && -kubectl wait --for=condition=Ready pod/tb-db-setup --timeout=120s && -kubectl exec tb-db-setup -- sh -c 'export UPGRADE_TB=true; export FROM_VERSION='"$fromVersion"'; start-tb-node.sh; touch /tmp/install-finished;' - -kubectl delete pod tb-db-setup From c0514ca3f4379a68206d1856cbfe952b34b5e7be Mon Sep 17 00:00:00 2001 From: Sergey Matvienko <79898499+smatvienko-tb@users.noreply.github.com> Date: Mon, 15 Nov 2021 10:03:01 +0200 Subject: [PATCH 252/303] Stats: do not persist empty stats (reducing event table size and disk IOPS) (#5554) * stats: do not persist empty stats * fixed license headers for stat actor and stat msg tests --- .../server/actors/stats/StatsActor.java | 3 + .../server/actors/stats/StatsPersistMsg.java | 5 ++ .../server/actors/stats/StatsActorTest.java | 69 +++++++++++++++++++ .../actors/stats/StatsPersistMsgTest.java | 38 ++++++++++ 4 files changed, 115 insertions(+) create mode 100644 application/src/test/java/org/thingsboard/server/actors/stats/StatsActorTest.java create mode 100644 application/src/test/java/org/thingsboard/server/actors/stats/StatsPersistMsgTest.java diff --git a/application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java b/application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java index a2ce3fe41f..5f4f100dac 100644 --- a/application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java @@ -51,6 +51,9 @@ public class StatsActor extends ContextAwareActor { } public void onStatsPersistMsg(StatsPersistMsg msg) { + if (msg.isEmpty()) { + return; + } Event event = new Event(); event.setEntityId(msg.getEntityId()); event.setTenantId(msg.getTenantId()); diff --git a/application/src/main/java/org/thingsboard/server/actors/stats/StatsPersistMsg.java b/application/src/main/java/org/thingsboard/server/actors/stats/StatsPersistMsg.java index 1f64c71629..b3863f88d9 100644 --- a/application/src/main/java/org/thingsboard/server/actors/stats/StatsPersistMsg.java +++ b/application/src/main/java/org/thingsboard/server/actors/stats/StatsPersistMsg.java @@ -37,4 +37,9 @@ public final class StatsPersistMsg implements TbActorMsg { public MsgType getMsgType() { return MsgType.STATS_PERSIST_MSG; } + + public boolean isEmpty() { + return messagesProcessed == 0 && errorsOccurred == 0; + } + } diff --git a/application/src/test/java/org/thingsboard/server/actors/stats/StatsActorTest.java b/application/src/test/java/org/thingsboard/server/actors/stats/StatsActorTest.java new file mode 100644 index 0000000000..c058bb881e --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/actors/stats/StatsActorTest.java @@ -0,0 +1,69 @@ +/** + * Copyright © 2016-2021 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.actors.stats; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.thingsboard.server.actors.ActorSystemContext; +import org.thingsboard.server.common.data.Event; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.event.EventService; +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.willReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +class StatsActorTest { + + StatsActor statsActor; + ActorSystemContext actorSystemContext; + EventService eventService; + TbServiceInfoProvider serviceInfoProvider; + + @BeforeEach + void setUp() { + actorSystemContext = mock(ActorSystemContext.class); + + eventService = mock(EventService.class); + willReturn(eventService).given(actorSystemContext).getEventService(); + serviceInfoProvider = mock(TbServiceInfoProvider.class); + willReturn(serviceInfoProvider).given(actorSystemContext).getServiceInfoProvider(); + + statsActor = new StatsActor(actorSystemContext); + } + + @Test + void givenEmptyStatMessage_whenOnStatsPersistMsg_thenNoAction() { + StatsPersistMsg emptyStats = new StatsPersistMsg(0, 0, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID); + statsActor.onStatsPersistMsg(emptyStats); + verify(actorSystemContext, never()).getEventService(); + } + + @Test + void givenNonEmptyStatMessage_whenOnStatsPersistMsg_thenNoAction() { + statsActor.onStatsPersistMsg(new StatsPersistMsg(0, 1, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID)); + verify(eventService, times(1)).save(any(Event.class)); + statsActor.onStatsPersistMsg(new StatsPersistMsg(1, 0, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID)); + verify(eventService, times(2)).save(any(Event.class)); + statsActor.onStatsPersistMsg(new StatsPersistMsg(1, 1, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID)); + verify(eventService, times(3)).save(any(Event.class)); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/actors/stats/StatsPersistMsgTest.java b/application/src/test/java/org/thingsboard/server/actors/stats/StatsPersistMsgTest.java new file mode 100644 index 0000000000..e4fcf7cfc4 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/actors/stats/StatsPersistMsgTest.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2021 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.actors.stats; + +import org.junit.jupiter.api.Test; +import org.thingsboard.server.common.data.id.TenantId; + +import static org.assertj.core.api.Assertions.assertThat; + +class StatsPersistMsgTest { + + @Test + void testIsEmpty() { + StatsPersistMsg emptyStats = new StatsPersistMsg(0, 0, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID); + assertThat(emptyStats.isEmpty()).isTrue(); + } + + @Test + void testNotEmpty() { + assertThat(new StatsPersistMsg(1, 0, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isEmpty()).isFalse(); + assertThat(new StatsPersistMsg(0, 1, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isEmpty()).isFalse(); + assertThat(new StatsPersistMsg(1, 1, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isEmpty()).isFalse(); + } + +} From 77b9a8c1af31bc8e3c988c7d77a6113f602c649f Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 16 Nov 2021 14:32:52 +0200 Subject: [PATCH 253/303] Minor improvements to the thingsboard.yml comments --- application/src/main/resources/thingsboard.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 90b52c8b02..85394e67a8 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -211,7 +211,7 @@ cassandra: init_retry_interval_ms: "${CASSANDRA_CLUSTER_INIT_RETRY_INTERVAL_MS:3000}" max_requests_per_connection_local: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_LOCAL:32768}" max_requests_per_connection_remote: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_REMOTE:32768}" - # Credential parameters # + # Credential parameters credentials: "${CASSANDRA_USE_CREDENTIALS:false}" # Specify your username username: "${CASSANDRA_USERNAME:}" @@ -595,7 +595,7 @@ js: remote: # Maximum allowed JavaScript execution errors before JavaScript will be blacklisted max_errors: "${REMOTE_JS_SANDBOX_MAX_ERRORS:3}" - # Maximum time in seconds for black listed function to stay in 1:the list. + # Maximum time in seconds for black listed function to stay in the list. max_black_list_duration_sec: "${REMOTE_JS_SANDBOX_MAX_BLACKLIST_DURATION_SEC:60}" stats: enabled: "${TB_JS_REMOTE_STATS_ENABLED:false}" @@ -1030,8 +1030,8 @@ queue: # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries; - max-pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:3}"# Max allowed time in seconds for pause between retries. + pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}" # Time in seconds to wait in consumer thread before retries; + max-pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:3}" # Max allowed time in seconds for pause between retries. - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" @@ -1047,8 +1047,8 @@ queue: # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - max-pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}"# Max allowed time in seconds for pause between retries. + pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}" # Time in seconds to wait in consumer thread before retries; + max-pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}" # Max allowed time in seconds for pause between retries. - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" @@ -1064,8 +1064,8 @@ queue: # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - max-pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}"# Max allowed time in seconds for pause between retries. + pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}" # Time in seconds to wait in consumer thread before retries; + max-pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}" # Max allowed time in seconds for pause between retries. transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" From 52578645b86fb9591bf8bf461c4c36b27731fe34 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 17 Nov 2021 12:13:05 +0200 Subject: [PATCH 254/303] added ability to configure network configuration for lwm2m --- application/src/main/resources/thingsboard.yml | 3 +++ .../thingsboard/server/common/data/TbProperty.java} | 4 ++-- .../server/queue/kafka/TbKafkaSettings.java | 5 +++-- .../lwm2m/config/LwM2MTransportServerConfig.java | 11 +++++++---- .../transport/lwm2m/server/LwM2mNetworkConfig.java | 9 +++++++-- .../lwm2m/src/main/resources/tb-lwm2m-transport.yml | 3 +++ 6 files changed, 25 insertions(+), 10 deletions(-) rename common/{queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProperty.java => data/src/main/java/org/thingsboard/server/common/data/TbProperty.java} (90%) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 85394e67a8..1273555176 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -819,6 +819,9 @@ transport: log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" + network_config: + - key: "PROTOCOL_STAGE_THREAD_COUNT" + value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:12}" snmp: enabled: "${SNMP_ENABLED:true}" response_processing: diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProperty.java b/common/data/src/main/java/org/thingsboard/server/common/data/TbProperty.java similarity index 90% rename from common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProperty.java rename to common/data/src/main/java/org/thingsboard/server/common/data/TbProperty.java index 993142850d..4824915521 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProperty.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TbProperty.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.queue.kafka; +package org.thingsboard.server.common.data; import lombok.Data; @@ -21,7 +21,7 @@ import lombok.Data; * Created by ashvayka on 25.09.18. */ @Data -public class TbKafkaProperty { +public class TbProperty { private String key; private String value; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java index 5dd7c40ba8..0dbb2401b3 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.TbProperty; import java.util.Collections; import java.util.List; @@ -104,10 +105,10 @@ public class TbKafkaSettings { private String securityProtocol; @Setter - private List other; + private List other; @Setter - private Map> consumerPropertiesPerTopic = Collections.emptyMap(); + private Map> consumerPropertiesPerTopic = Collections.emptyMap(); public Properties toAdminProps() { Properties props = toProps(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index f444b74c2b..e5ef613495 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -25,17 +25,16 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.ResourceUtils; +import org.thingsboard.server.common.data.TbProperty; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; -import javax.annotation.PostConstruct; -import java.io.InputStream; -import java.security.KeyStore; +import java.util.List; @Slf4j @Component @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +@ConfigurationProperties(prefix = "transport.lwm2m") public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Getter @@ -102,6 +101,10 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Value("${transport.lwm2m.paging_transmission_window:10000}") private long pagingTransmissionWindow; + @Getter + @Setter + private List networkConfig; + @Bean @ConfigurationProperties(prefix = "transport.lwm2m.server.security.credentials") public SslCredentialsConfig lwm2mServerCredentials() { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java index 4fc60aecfc..2b488a3ab9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.core.network.config.NetworkConfigDefaults; +import org.springframework.util.CollectionUtils; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; @@ -25,8 +26,8 @@ public class LwM2mNetworkConfig { public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) { NetworkConfig coapConfig = new NetworkConfig(); - coapConfig.setInt(NetworkConfig.Keys.COAP_PORT,serverPortNoSec); - coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT,serverSecurePort); + coapConfig.setInt(NetworkConfig.Keys.COAP_PORT, serverPortNoSec); + coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, serverSecurePort); /** Example:Property for large packet: #NetworkConfig config = new NetworkConfig(); @@ -105,6 +106,10 @@ public class LwM2mNetworkConfig { coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10); + if (!CollectionUtils.isEmpty(config.getNetworkConfig())) { + config.getNetworkConfig().forEach(p -> coapConfig.setString(p.getKey(), p.getValue())); + } + return coapConfig; } } \ No newline at end of file diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 8864b99e8c..34c08029b0 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -204,6 +204,9 @@ transport: paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" + network_config: + - key: "PROTOCOL_STAGE_THREAD_COUNT" + value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:12}" stats: enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" From a9151b5100539b0ce4a734726eb1aacbbe3a22dc Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 19 Nov 2021 17:54:16 +0200 Subject: [PATCH 255/303] fixed NPE --- .../server/client/LwM2mClientContextImpl.java | 4 +- .../rpc/DefaultLwM2MRpcRequestHandler.java | 162 +++++++++--------- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index f89edb6353..da304821da 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -278,8 +278,8 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { LwM2mClient lwM2mClient = null; UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); - Predicate isClientFilter = c -> - sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))); + Predicate isClientFilter = + c -> c.getSession() != null && sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))); if (this.lwM2mClientsByEndpoint.size() > 0) { lwM2mClient = this.lwM2mClientsByEndpoint.values().stream().filter(isClientFilter).findAny().orElse(null); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 118961850c..161ca3d2f1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -17,15 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.request.ReadCompositeRequest; -import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -63,11 +60,9 @@ import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadRespon import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; -import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; @Slf4j @Service @@ -85,91 +80,96 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { @Override public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequest, TransportProtos.SessionInfoProto sessionInfo) { log.debug("Received params: {}", rpcRequest.getParams()); - LwM2mOperationType operationType = LwM2mOperationType.fromType(rpcRequest.getMethodName()); - if (operationType == null) { - this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED, "Unsupported operation type: " + rpcRequest.getMethodName()); - return; - } - LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); - if (client.getRegistration() == null) { - this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); - return; - } - UUID rpcId = new UUID(rpcRequest.getRequestIdMSB(), rpcRequest.getRequestIdLSB()); - - if (rpcId.equals(client.getLastSentRpcId())) { - log.debug("[{}]][{}] Rpc has already sent!", client.getEndpoint(), rpcId); - return; - } try { - if (operationType.isHasObjectId()) { - String objectId = getIdFromParameters(client, rpcRequest); - switch (operationType) { - case READ: - sendReadRequest(client, rpcRequest, objectId); - break; - case OBSERVE: - sendObserveRequest(client, rpcRequest, objectId); - break; - case DISCOVER: - sendDiscoverRequest(client, rpcRequest, objectId); - break; - case EXECUTE: - sendExecuteRequest(client, rpcRequest, objectId); - break; - case WRITE_ATTRIBUTES: - sendWriteAttributesRequest(client, rpcRequest, objectId); - break; - case OBSERVE_CANCEL: - sendCancelObserveRequest(client, rpcRequest, objectId); - break; - case DELETE: - sendDeleteRequest(client, rpcRequest, objectId); - break; - case WRITE_UPDATE: - sendWriteUpdateRequest(client, rpcRequest, objectId); - break; - case WRITE_REPLACE: - sendWriteReplaceRequest(client, rpcRequest, objectId); - break; - default: - throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); - } - } else if (operationType.isComposite()) { - if (clientContext.isComposite(client)) { + LwM2mOperationType operationType = LwM2mOperationType.fromType(rpcRequest.getMethodName()); + if (operationType == null) { + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED, "Unsupported operation type: " + rpcRequest.getMethodName()); + return; + } + LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); + if (client.getRegistration() == null) { + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); + return; + } + UUID rpcId = new UUID(rpcRequest.getRequestIdMSB(), rpcRequest.getRequestIdLSB()); + + if (rpcId.equals(client.getLastSentRpcId())) { + log.debug("[{}]][{}] Rpc has already sent!", client.getEndpoint(), rpcId); + return; + } + try { + if (operationType.isHasObjectId()) { + String objectId = getIdFromParameters(client, rpcRequest); switch (operationType) { - case READ_COMPOSITE: - sendReadCompositeRequest(client, rpcRequest); + case READ: + sendReadRequest(client, rpcRequest, objectId); + break; + case OBSERVE: + sendObserveRequest(client, rpcRequest, objectId); + break; + case DISCOVER: + sendDiscoverRequest(client, rpcRequest, objectId); + break; + case EXECUTE: + sendExecuteRequest(client, rpcRequest, objectId); + break; + case WRITE_ATTRIBUTES: + sendWriteAttributesRequest(client, rpcRequest, objectId); break; - case WRITE_COMPOSITE: - sendWriteCompositeRequest(client, rpcRequest); + case OBSERVE_CANCEL: + sendCancelObserveRequest(client, rpcRequest, objectId); + break; + case DELETE: + sendDeleteRequest(client, rpcRequest, objectId); + break; + case WRITE_UPDATE: + sendWriteUpdateRequest(client, rpcRequest, objectId); + break; + case WRITE_REPLACE: + sendWriteReplaceRequest(client, rpcRequest, objectId); break; default: throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } + } else if (operationType.isComposite()) { + if (clientContext.isComposite(client)) { + switch (operationType) { + case READ_COMPOSITE: + sendReadCompositeRequest(client, rpcRequest); + break; + case WRITE_COMPOSITE: + sendWriteCompositeRequest(client, rpcRequest); + break; + default: + throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); + } + } else { + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), + ResponseCode.INTERNAL_SERVER_ERROR, "This device does not support Composite Operation"); + } } else { - this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), - ResponseCode.INTERNAL_SERVER_ERROR, "This device does not support Composite Operation"); - } - } else { - switch (operationType) { - case OBSERVE_CANCEL_ALL: - sendCancelAllObserveRequest(client, rpcRequest); - break; - case OBSERVE_READ_ALL: - sendObserveAllRequest(client, rpcRequest); - break; - case DISCOVER_ALL: - sendDiscoverAllRequest(client, rpcRequest); - break; - case FW_UPDATE: - //TODO: implement and add break statement - default: - throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); + switch (operationType) { + case OBSERVE_CANCEL_ALL: + sendCancelAllObserveRequest(client, rpcRequest); + break; + case OBSERVE_READ_ALL: + sendObserveAllRequest(client, rpcRequest); + break; + case DISCOVER_ALL: + sendDiscoverAllRequest(client, rpcRequest); + break; + case FW_UPDATE: + //TODO: implement and add break statement + default: + throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); + } } + } catch (IllegalArgumentException e) { + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.BAD_REQUEST, e.getMessage()); } - } catch (IllegalArgumentException e) { - this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.BAD_REQUEST, e.getMessage()); + } catch (Exception e) { + log.error("[{}] Failed to send RPC: [{}]", sessionInfo, rpcRequest, e); + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, ExceptionUtils.getRootCauseMessage(e)); } } From 5da827bf4859265116a953affe6ad86f3d83496f Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Mon, 22 Nov 2021 17:02:16 +0200 Subject: [PATCH 256/303] UI: Fix layout for firefox --- .../widget/widget-config.component.html | 39 ++++++++----------- .../widget/widget-config.component.scss | 9 +++++ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 761603a3ee..97542fd3cb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -295,8 +295,7 @@ widget-config.data-settings -
        +
        widget-config.units @@ -320,13 +319,12 @@
        -
        +
        widget-config.title - + {{ 'widget-config.display-title' | translate }} -
        +
        widget-config.title @@ -336,13 +334,12 @@
        -
        +
        widget-config.title-icon - + {{ 'widget-config.display-icon' | translate }} -
        +
        @@ -374,12 +371,10 @@
        -
        +
        widget-config.widget-style -
        -
        +
        +
        -
        +
        widget-config.padding @@ -405,10 +399,10 @@
        - + {{ 'widget-config.drop-shadow' | translate }} - + {{ 'widget-config.enable-fullscreen' | translate }} @@ -427,7 +421,7 @@
        -
        +
        widget-config.legend @@ -445,7 +439,7 @@
        -
        +
        widget-config.mobile-mode-settings @@ -459,8 +453,7 @@ -
        +
        widget-config.order diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss index 8d8cd742c6..c29afa5629 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss @@ -201,6 +201,15 @@ } } } + .mat-slide { + margin: 8px 0; + } + .slide-block { + display: block; + &:not(:last-child) { + margin-bottom: 8px; + } + } .mat-slide-toggle-content { white-space: normal; } From 3ffd62f8443aed8e02938ba360aa50e57cdd583e Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 24 Nov 2021 09:36:14 +0200 Subject: [PATCH 257/303] Fix corner case when access token matches user name in credentials --- .../BasicCredentialsValidationResult.java | 18 ++ .../transport/DefaultTransportApiService.java | 95 +++++--- .../transport/TransportSqlTestSuite.java | 1 + .../credentials/BasicMqttCredentialsTest.java | 226 ++++++++++++++++++ .../dao/device/DeviceCredentialsService.java | 3 + 5 files changed, 306 insertions(+), 37 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/transport/BasicCredentialsValidationResult.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java diff --git a/application/src/main/java/org/thingsboard/server/service/transport/BasicCredentialsValidationResult.java b/application/src/main/java/org/thingsboard/server/service/transport/BasicCredentialsValidationResult.java new file mode 100644 index 0000000000..56d7b776e8 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/transport/BasicCredentialsValidationResult.java @@ -0,0 +1,18 @@ +/** + * Copyright © 2016-2021 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.transport; + +enum BasicCredentialsValidationResult {HASH_MISMATCH, PASSWORD_MISMATCH, VALID} diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index dc5f6c436d..1cefefd5d1 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -25,7 +25,6 @@ import com.google.protobuf.ByteString; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.ApiUsageState; @@ -37,6 +36,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.ResourceType; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; @@ -107,6 +107,9 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; +import static org.thingsboard.server.service.transport.BasicCredentialsValidationResult.PASSWORD_MISMATCH; +import static org.thingsboard.server.service.transport.BasicCredentialsValidationResult.VALID; + /** * Created by ashvayka on 05.10.18. */ @@ -181,71 +184,89 @@ public class DefaultTransportApiService implements TransportApiService { //TODO: Make async and enable caching DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(credentialsId); if (credentials != null && credentials.getCredentialsType() == credentialsType) { - return getDeviceInfo(credentials.getDeviceId(), credentials); + return getDeviceInfo(credentials); } else { return getEmptyTransportApiResponseFuture(); } } private ListenableFuture validateCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg mqtt) { - DeviceCredentials credentials = null; - if (!StringUtils.isEmpty(mqtt.getUserName())) { - credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName()); + DeviceCredentials credentials; + if (StringUtils.isEmpty(mqtt.getUserName())) { + credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash(mqtt.getClientId())); if (credentials != null) { - if (credentials.getCredentialsType() == DeviceCredentialsType.ACCESS_TOKEN) { - return getDeviceInfo(credentials.getDeviceId(), credentials); - } else if (credentials.getCredentialsType() == DeviceCredentialsType.MQTT_BASIC) { - if (!checkMqttCredentials(mqtt, credentials)) { - credentials = null; - } - } else { + return getDeviceInfo(credentials); + } else { + return getEmptyTransportApiResponseFuture(); + } + } else { + credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId( + EncryptionUtil.getSha3Hash("|", mqtt.getClientId(), mqtt.getUserName())); + if (checkIsMqttCredentials(credentials)) { + var validationResult = validateMqttCredentials(mqtt, credentials); + if (VALID.equals(validationResult)) { + return getDeviceInfo(credentials); + } else if (PASSWORD_MISMATCH.equals(validationResult)) { return getEmptyTransportApiResponseFuture(); + } else { + return validateUserNameCredentials(mqtt); } + } else { + return validateUserNameCredentials(mqtt); } - if (credentials == null) { - credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash("|", mqtt.getClientId(), mqtt.getUserName())); - } - } - if (credentials == null) { - credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash(mqtt.getClientId())); } + } + + private ListenableFuture validateUserNameCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg mqtt) { + DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName()); if (credentials != null) { - return getDeviceInfo(credentials.getDeviceId(), credentials); - } else { - return getEmptyTransportApiResponseFuture(); + switch (credentials.getCredentialsType()) { + case ACCESS_TOKEN: + return getDeviceInfo(credentials); + case MQTT_BASIC: + if (VALID.equals(validateMqttCredentials(mqtt, credentials))) { + return getDeviceInfo(credentials); + } else { + return getEmptyTransportApiResponseFuture(); + } + } } + return getEmptyTransportApiResponseFuture(); + } + + private static boolean checkIsMqttCredentials(DeviceCredentials credentials) { + return credentials != null && DeviceCredentialsType.MQTT_BASIC.equals(credentials.getCredentialsType()); } private DeviceCredentials checkMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, String credId) { - DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(credId); + return checkMqttCredentials(clientCred, deviceCredentialsService.findDeviceCredentialsByCredentialsId(credId)); + } + + private DeviceCredentials checkMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, DeviceCredentials deviceCredentials) { if (deviceCredentials != null && deviceCredentials.getCredentialsType() == DeviceCredentialsType.MQTT_BASIC) { - if (!checkMqttCredentials(clientCred, deviceCredentials)) { - return null; - } else { + if (VALID.equals(validateMqttCredentials(clientCred, deviceCredentials))) { return deviceCredentials; } } return null; } - private boolean checkMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, DeviceCredentials deviceCredentials) { + private BasicCredentialsValidationResult validateMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, DeviceCredentials deviceCredentials) { BasicMqttCredentials dbCred = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), BasicMqttCredentials.class); if (!StringUtils.isEmpty(dbCred.getClientId()) && !dbCred.getClientId().equals(clientCred.getClientId())) { - return false; + return BasicCredentialsValidationResult.HASH_MISMATCH; } if (!StringUtils.isEmpty(dbCred.getUserName()) && !dbCred.getUserName().equals(clientCred.getUserName())) { - return false; + return BasicCredentialsValidationResult.HASH_MISMATCH; } if (!StringUtils.isEmpty(dbCred.getPassword())) { if (StringUtils.isEmpty(clientCred.getPassword())) { - return false; + return BasicCredentialsValidationResult.PASSWORD_MISMATCH; } else { - if (!dbCred.getPassword().equals(clientCred.getPassword())) { - return false; - } + return dbCred.getPassword().equals(clientCred.getPassword()) ? VALID : BasicCredentialsValidationResult.PASSWORD_MISMATCH; } } - return true; + return VALID; } private ListenableFuture handle(GetOrCreateDeviceFromGatewayRequestMsg requestMsg) { @@ -437,10 +458,10 @@ public class DefaultTransportApiService implements TransportApiService { .build()); } - private ListenableFuture getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { - return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> { + private ListenableFuture getDeviceInfo(DeviceCredentials credentials) { + return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, credentials.getDeviceId()), device -> { if (device == null) { - log.trace("[{}] Failed to lookup device by id", deviceId); + log.trace("[{}] Failed to lookup device by id", credentials.getDeviceId()); return getEmptyTransportApiResponse(); } try { @@ -458,7 +479,7 @@ public class DefaultTransportApiService implements TransportApiService { return TransportApiResponseMsg.newBuilder() .setValidateCredResponseMsg(builder.build()).build(); } catch (JsonProcessingException e) { - log.warn("[{}] Failed to lookup device by id", deviceId, e); + log.warn("[{}] Failed to lookup device by id", credentials.getDeviceId(), e); return getEmptyTransportApiResponse(); } }, MoreExecutors.directExecutor()); diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index 0fa04d0611..dc5f5917dc 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -33,6 +33,7 @@ import java.util.Arrays; "org.thingsboard.server.transport.*.attributes.request.sql.*Test", "org.thingsboard.server.transport.*.claim.sql.*Test", "org.thingsboard.server.transport.*.provision.sql.*Test", + "org.thingsboard.server.transport.*.credentials.*Test", "org.thingsboard.server.transport.lwm2m.sql.*Test" }) public class TransportSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java new file mode 100644 index 0000000000..32ae17e94d --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java @@ -0,0 +1,226 @@ +/** + * Copyright © 2016-2021 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.transport.mqtt.credentials; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; +import org.eclipse.paho.client.mqttv3.MqttAsyncClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttSecurityException; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@DaoSqlTest +public class BasicMqttCredentialsTest extends AbstractMqttIntegrationTest { + + public static final String CLIENT_ID = "ClientId"; + public static final String USER_NAME1 = "UserName1"; + public static final String USER_NAME2 = "UserName2"; + public static final String USER_NAME3 = "UserName3"; + public static final String PASSWORD = "secret"; + + private Device clientIdDevice; + private Device clientIdAndUserNameDevice1; + private Device clientIdAndUserNameAndPasswordDevice2; + private Device clientIdAndUserNameAndPasswordDevice3; + private Device accessTokenDevice; + private Device accessToken2Device; + + + @Before + public void before() throws Exception { + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant" + atomicInteger.getAndIncrement() + "@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + + BasicMqttCredentials credValue = new BasicMqttCredentials(); + credValue.setClientId(CLIENT_ID); + clientIdDevice = createDevice("clientIdDevice", credValue); + + credValue = new BasicMqttCredentials(); + credValue.setClientId(CLIENT_ID); + credValue.setUserName(USER_NAME1); + clientIdAndUserNameDevice1 = createDevice("clientIdAndUserNameDevice", credValue); + + credValue = new BasicMqttCredentials(); + credValue.setClientId(CLIENT_ID); + credValue.setUserName(USER_NAME2); + credValue.setPassword(PASSWORD); + clientIdAndUserNameAndPasswordDevice2 = createDevice("clientIdAndUserNameAndPasswordDevice", credValue); + + credValue = new BasicMqttCredentials(); + credValue.setClientId(CLIENT_ID); + credValue.setUserName(USER_NAME3); + credValue.setPassword(PASSWORD); + clientIdAndUserNameAndPasswordDevice3 = createDevice("clientIdAndUserNameAndPasswordDevice2", credValue); + + accessTokenDevice = createDevice("accessTokenDevice", USER_NAME1); + accessToken2Device = createDevice("accessToken2Device", USER_NAME2); + } + + @Test + public void testCorrectCredentials() throws Exception { + // Check that correct devices receive telemetry + testTelemetryIsDelivered(accessTokenDevice, getMqttAsyncClient(null, USER_NAME1, null)); + testTelemetryIsDelivered(clientIdDevice, getMqttAsyncClient(CLIENT_ID, null, null)); + testTelemetryIsDelivered(clientIdAndUserNameDevice1, getMqttAsyncClient(CLIENT_ID, USER_NAME1, null)); + testTelemetryIsDelivered(clientIdAndUserNameAndPasswordDevice2, getMqttAsyncClient(CLIENT_ID, USER_NAME2, PASSWORD)); + + // Also correct. Random clientId and password, but matches access token + testTelemetryIsDelivered(accessToken2Device, getMqttAsyncClient(RandomStringUtils.randomAlphanumeric(10), USER_NAME2, RandomStringUtils.randomAlphanumeric(10))); + } + + @Test(expected = MqttSecurityException.class) + public void testCorrectClientIdAndUserNameButWrongPassword() throws Exception { + // Not correct. Correct clientId and username, but wrong password + testTelemetryIsNotDelivered(clientIdAndUserNameAndPasswordDevice3, getMqttAsyncClient(CLIENT_ID, USER_NAME3, "WRONG PASSWORD")); + } + + private void testTelemetryIsDelivered(Device device, MqttAsyncClient client) throws Exception { + testTelemetryIsDelivered(device, client, true); + } + + private void testTelemetryIsNotDelivered(Device device, MqttAsyncClient client) throws Exception { + testTelemetryIsDelivered(device, client, false); + } + + private void testTelemetryIsDelivered(Device device, MqttAsyncClient client, boolean ok) throws Exception { + String randomKey = RandomStringUtils.randomAlphanumeric(10); + List expectedKeys = Arrays.asList(randomKey); + publishMqttMsg(client, JacksonUtil.toString(JacksonUtil.newObjectNode().put(randomKey, true)).getBytes(), MqttTopics.DEVICE_TELEMETRY_TOPIC); + + String deviceId = device.getId().getId().toString(); + + long start = System.currentTimeMillis(); + long end = System.currentTimeMillis() + 5000; + + List actualKeys = null; + while (start <= end) { + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", new TypeReference<>() { + }); + if (actualKeys.size() == expectedKeys.size()) { + break; + } + Thread.sleep(100); + start += 100; + } + if (ok) { + assertNotNull(actualKeys); + + Set actualKeySet = new HashSet<>(actualKeys); + Set expectedKeySet = new HashSet<>(expectedKeys); + + assertEquals(expectedKeySet, actualKeySet); + } else { + assertNull(actualKeys); + } + client.disconnect().waitForCompletion(); + } + + @After + public void after() throws Exception { + processAfterTest(); + } + + protected MqttAsyncClient getMqttAsyncClient(String clientId, String username, String password) throws MqttException { + if (StringUtils.isEmpty(clientId)) { + clientId = MqttAsyncClient.generateClientId(); + } + MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence()); + + MqttConnectOptions options = new MqttConnectOptions(); + if (StringUtils.isNotEmpty(username)) { + options.setUserName(username); + } + if (StringUtils.isNotEmpty(password)) { + options.setPassword(password.toCharArray()); + } + client.connect(options).waitForCompletion(); + return client; + } + + private Device createDevice(String deviceName, BasicMqttCredentials clientIdCredValue) throws Exception { + Device device = new Device(); + device.setName(deviceName); + device.setType("default"); + + device = doPost("/api/device", device, Device.class); + + DeviceCredentials clientIdCred = + doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); + + clientIdCred.setCredentialsType(DeviceCredentialsType.MQTT_BASIC); + + + clientIdCred.setCredentialsValue(JacksonUtil.toString(clientIdCredValue)); + doPost("/api/device/credentials", clientIdCred).andExpect(status().isOk()); + return device; + } + + private Device createDevice(String deviceName, String accessToken) throws Exception { + Device device = new Device(); + device.setName(deviceName); + device.setType("default"); + + device = doPost("/api/device", device, Device.class); + + DeviceCredentials clientIdCred = + doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); + + clientIdCred.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); + clientIdCred.setCredentialsId(accessToken); + doPost("/api/device/credentials", clientIdCred).andExpect(status().isOk()); + return device; + } +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java index 29572bf51a..9afc735213 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java @@ -19,6 +19,8 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.DeviceCredentials; +import java.util.List; + public interface DeviceCredentialsService { DeviceCredentials findDeviceCredentialsByDeviceId(TenantId tenantId, DeviceId deviceId); @@ -32,4 +34,5 @@ public interface DeviceCredentialsService { void formatCredentials(DeviceCredentials deviceCredentials); void deleteDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials); + } From 6d006d16c7522d8c59e1f51f4627c7f47f98430d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 24 Nov 2021 10:38:45 +0200 Subject: [PATCH 258/303] Improved rate limits message for MQTT session events --- .../server/common/msg/tools/TbRateLimitsException.java | 1 + .../thingsboard/server/transport/mqtt/MqttTransportHandler.java | 2 +- .../transport/limits/DefaultTransportRateLimitService.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java index 89b2c7b527..35d5ad63c4 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java @@ -26,6 +26,7 @@ public class TbRateLimitsException extends RuntimeException { private final EntityType entityType; public TbRateLimitsException(EntityType entityType) { + super(entityType.name() + " rate limits reached!"); this.entityType = entityType; } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 61638052c0..693b47d42f 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -951,7 +951,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onError(Throwable e) { if (e instanceof TbRateLimitsException) { - log.trace("[{}] Failed to submit session event", sessionId, e); + log.trace("[{}] Failed to submit session event: {}", sessionId, e.getMessage()); } else { log.warn("[{}] Failed to submit session event", sessionId, e); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java index e7d6cddc3c..5ee4064466 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java @@ -57,7 +57,7 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi @Override public EntityType checkLimits(TenantId tenantId, DeviceId deviceId, int dataPoints) { if (!tenantAllowed.getOrDefault(tenantId, Boolean.TRUE)) { - return EntityType.TENANT; + return EntityType.API_USAGE_STATE; } if (!checkEntityRateLimit(dataPoints, getTenantRateLimits(tenantId))) { return EntityType.TENANT; From 1c81f227b511aa5d5325b2ff537748c23d49d2bf Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 24 Nov 2021 11:19:58 +0200 Subject: [PATCH 259/303] Correct test class name according to mask in pom.xml --- .../org/thingsboard/server/transport/TransportSqlTestSuite.java | 2 +- .../mqtt/credentials/{ => sql}/BasicMqttCredentialsTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/{ => sql}/BasicMqttCredentialsTest.java (99%) diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index dc5f5917dc..8df7f22867 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -33,7 +33,7 @@ import java.util.Arrays; "org.thingsboard.server.transport.*.attributes.request.sql.*Test", "org.thingsboard.server.transport.*.claim.sql.*Test", "org.thingsboard.server.transport.*.provision.sql.*Test", - "org.thingsboard.server.transport.*.credentials.*Test", + "org.thingsboard.server.transport.*.credentials.sql.*Test", "org.thingsboard.server.transport.lwm2m.sql.*Test" }) public class TransportSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/sql/BasicMqttCredentialsTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/sql/BasicMqttCredentialsTest.java index 32ae17e94d..6bb8949f73 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/sql/BasicMqttCredentialsTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.credentials; +package org.thingsboard.server.transport.mqtt.credentials.sql; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.lang3.RandomStringUtils; From 7187ecfdb106f273d19e270129ac304e85dc5c85 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 24 Nov 2021 12:24:27 +0200 Subject: [PATCH 260/303] Version set to 3.3.3-SNAPSHOT --- application/pom.xml | 2 +- common/actor/pom.xml | 2 +- common/cache/pom.xml | 2 +- common/cluster-api/pom.xml | 2 +- common/coap-server/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/edge-api/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/lwm2m/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/snmp/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/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/lwm2m/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/transport/snmp/pom.xml | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rest-client/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/lwm2m/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- transport/snmp/pom.xml | 2 +- ui-ngx/pom.xml | 2 +- 47 files changed, 48 insertions(+), 48 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index cc3bcef183..beb931d9b0 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index 90e7bf22d0..16bd96eedb 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/cache/pom.xml b/common/cache/pom.xml index 1637621273..f5bf91c9f0 100644 --- a/common/cache/pom.xml +++ b/common/cache/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/cluster-api/pom.xml b/common/cluster-api/pom.xml index 4c59e022d4..6a337c414d 100644 --- a/common/cluster-api/pom.xml +++ b/common/cluster-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/coap-server/pom.xml b/common/coap-server/pom.xml index 945556c188..a8762a81d2 100644 --- a/common/coap-server/pom.xml +++ b/common/coap-server/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index b5d26b8781..f861d2fb63 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index 1b5c78bcd6..80be41e6a0 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/edge-api/pom.xml b/common/edge-api/pom.xml index 4223b92d70..482e9d77d8 100644 --- a/common/edge-api/pom.xml +++ b/common/edge-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index 1916aeb254..92c216d7b0 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 233046824d..b318d57a4e 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 41937ac079..a43e5c0188 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 8501fea19a..2af921b251 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index a1e1aaa2b0..26f1f45a0f 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 24e3ce2337..2164a5c58e 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 6ae5747501..33e7138e33 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 5d93b95615..0136730eb3 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index 113e7b46a9..d82fac0264 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/snmp/pom.xml b/common/transport/snmp/pom.xml index 12576e9a54..7b3535db82 100644 --- a/common/transport/snmp/pom.xml +++ b/common/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index b66676e61c..df14a28436 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 - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index a49b602c19..2109d090b1 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index f490a0e8e5..6a01c08822 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index b642f5a2c5..5a0645c03a 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index f08a17987a..5cabaed58a 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index af70451a1e..024607378c 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 90b8e4ede6..9cf97b4906 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index f55f5b12e5..841a4edbdf 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index f6e226802a..34b37c6334 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index b14fa3b82f..0cc5320250 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml index c02dc88e7e..2dd44c4386 100644 --- a/msa/transport/lwm2m/pom.xml +++ b/msa/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 9258221754..d483ef42eb 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 3a19267950..06c1d17939 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/snmp/pom.xml b/msa/transport/snmp/pom.xml index 7be1e011a2..a30942fe4c 100644 --- a/msa/transport/snmp/pom.xml +++ b/msa/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.msa transport - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT org.thingsboard.msa.transport diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 0a231344de..2b973afaba 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 93ccb59913..e6c2843b14 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard netty-mqtt - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 7503bcc4c0..7b3dd97ce8 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 87d3b6fa9d..36ec99fab6 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 941188b24a..986ac17cae 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 1465ac1fd8..03510ab9ce 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 - 3.3.2-SNAPSHOT + 3.3.3-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 c34d6b3df6..2be6f0cdba 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 - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 51c4dd689b..b68e4b94a3 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index cf54bcb496..cb0bb5e5ee 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 4dd04c1932..7b92d5135f 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index 4730be97bd..1b7ed8f6ca 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index dc2310f62e..1eac98020b 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index 9347afe94f..8b19669740 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard transport diff --git a/transport/snmp/pom.xml b/transport/snmp/pom.xml index 72201e25dd..520c651c32 100644 --- a/transport/snmp/pom.xml +++ b/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index 59e85024fd..d071908001 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard org.thingsboard From a3146b69870210cc4077269ba1ec3b72d7ee5142 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 24 Nov 2021 12:25:24 +0200 Subject: [PATCH 261/303] Version set to 3.3.3 --- msa/js-executor/package.json | 2 +- msa/web-ui/package.json | 2 +- ui-ngx/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 5c9924dd50..9fe84ffa9f 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "3.3.2", + "version": "3.3.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 b984118482..cc98e5f457 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "3.3.2", + "version": "3.3.3", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 519d31b66c..73d8e8e7b7 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "3.3.2", + "version": "3.3.3", "scripts": { "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", From 2e8b9b5cd7b66a6420b87480ea11ed0a1bbdcdc5 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 24 Nov 2021 13:03:52 +0200 Subject: [PATCH 262/303] UI: Improvement add/edit location marker/polygon in maps widgets --- pom.xml | 1 + ui-ngx/angular.json | 1 + ui-ngx/package.json | 17 +- .../select-entity-dialog.component.html | 54 ++ .../select-entity-dialog.component.scss | 21 + .../dialogs/select-entity-dialog.component.ts | 56 +++ .../components/widget/lib/maps/leaflet-map.ts | 469 ++++++++++-------- .../components/widget/lib/maps/map-models.ts | 1 + .../components/widget/lib/maps/map-widget2.ts | 130 +---- .../components/widget/lib/maps/markers.scss | 6 +- .../components/widget/lib/maps/markers.ts | 31 +- .../components/widget/lib/maps/polygon.ts | 19 +- .../components/widget/lib/maps/polyline.ts | 12 +- .../widget/lib/maps/providers/google-map.ts | 1 - .../widget/lib/maps/providers/here-map.ts | 1 - .../widget/lib/maps/providers/image-map.ts | 21 +- .../lib/maps/providers/openstreet-map.ts | 1 - .../widget/lib/maps/providers/tencent-map.ts | 1 - .../components/widget/lib/maps/schemes.ts | 6 + .../trip-animation.component.ts | 6 +- .../widget/widget-components.module.ts | 4 +- ui-ngx/src/assets/add_location.svg | 1 - ui-ngx/src/assets/add_polygon.svg | 3 - .../assets/locale/locale.constant-en_US.json | 35 +- ui-ngx/src/assets/shadow.png | Bin 0 -> 712 bytes ui-ngx/src/tsconfig.app.json | 2 +- ...marker.d.ts => leaflet-geoman-extend.d.ts} | 18 +- ui-ngx/tsconfig.json | 3 +- ui-ngx/yarn.lock | 282 +++++++++-- 29 files changed, 758 insertions(+), 445 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts delete mode 100644 ui-ngx/src/assets/add_location.svg delete mode 100644 ui-ngx/src/assets/add_polygon.svg create mode 100644 ui-ngx/src/assets/shadow.png rename ui-ngx/src/typings/{add-marker.d.ts => leaflet-geoman-extend.d.ts} (72%) diff --git a/pom.xml b/pom.xml index 7503bcc4c0..cf348e2f4a 100755 --- a/pom.xml +++ b/pom.xml @@ -830,6 +830,7 @@ src/.browserslistrc **/yarn.lock **/*.raw + **/*.patch **/apache/cassandra/io/** .run/** diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index a97e65b04c..0d6203c88e 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -79,6 +79,7 @@ "src/app/modules/home/components/widget/lib/maps/markers.scss", "node_modules/leaflet.markercluster/dist/MarkerCluster.css", "node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css", + "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css", "node_modules/prismjs/themes/prism.css", "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css" ], diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 519d31b66c..f9ca6d478c 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -28,6 +28,7 @@ "@date-io/date-fns": "^2.10.11", "@flowjs/flow.js": "^2.14.1", "@flowjs/ngx-flow": "~0.4.6", + "@geoman-io/leaflet-geoman-free": "^2.11.3", "@juggle/resize-observer": "^3.3.1", "@mat-datetimepicker/core": "~6.0.2", "@material-ui/core": "^4.11.4", @@ -57,11 +58,10 @@ "jstree-bootstrap-theme": "^1.0.1", "jszip": "^3.6.0", "leaflet": "^1.7.1", - "leaflet-editable": "^1.2.0", "leaflet-polylinedecorator": "^1.6.0", - "leaflet-providers": "^1.12.0", - "leaflet.gridlayer.googlemutant": "0.10.2", - "leaflet.markercluster": "^1.5.0", + "leaflet-providers": "^1.13.0", + "leaflet.gridlayer.googlemutant": "^0.13.4", + "leaflet.markercluster": "^1.5.3", "material-design-icons": "^3.0.1", "messageformat": "^2.3.0", "moment": "^2.29.1", @@ -113,10 +113,11 @@ "@types/jquery": "^3.5.2", "@types/js-beautify": "^1.13.1", "@types/jstree": "^3.3.40", - "@types/leaflet": "1.5.17", - "@types/leaflet-editable": "^1.2.1", - "@types/leaflet-polylinedecorator": "^1.6.0", - "@types/leaflet.markercluster": "^1.4.4", + "@types/leaflet": "^1.7.6", + "@types/leaflet-polylinedecorator": "^1.6.1", + "@types/leaflet-providers": "^1.2.1", + "@types/leaflet.gridlayer.googlemutant": "^0.4.6", + "@types/leaflet.markercluster": "^1.4.6", "@types/lodash": "^4.14.170", "@types/moment-timezone": "^0.5.30", "@types/mousetrap": "1.6.3", diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html new file mode 100644 index 0000000000..93fa72c84b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html @@ -0,0 +1,54 @@ + +
        + +

        widgets.maps.select-entity

        + + +
        + + +
        +
        + + entity.entity + + + {{ entity.entityName }} + + + +
        widgets.maps.select-entity-hint
        +
        +
        + + +
        +
        diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss new file mode 100644 index 0000000000..b9600d8731 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss @@ -0,0 +1,21 @@ +/** + * Copyright © 2016-2021 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. + */ +:host { + .tb-hint { + margin-top: -1.25em; + max-width: fit-content; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts new file mode 100644 index 0000000000..58526a4e66 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts @@ -0,0 +1,56 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Inject } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { FormattedData } from '@home/components/widget/lib/maps/map-models'; + +export interface SelectEntityDialogData { + entities: FormattedData[]; +} + +@Component({ + selector: 'tb-select-entity-dialog', + templateUrl: './select-entity-dialog.component.html', + styleUrls: ['./select-entity-dialog.component.scss'] +}) +export class SelectEntityDialogComponent extends DialogComponent { + + selectEntityFormGroup: FormGroup; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: SelectEntityDialogData, + public dialogRef: MatDialogRef, + public fb: FormBuilder) { + super(store, router, dialogRef); + + this.selectEntityFormGroup = this.fb.group( + { + entity: ['', Validators.required] + } + ); + } + + save(): void { + this.dialogRef.close(this.selectEntityFormGroup.value.entity); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 5120fc8c9e..03249a5307 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -14,23 +14,15 @@ /// limitations under the License. /// -import L, { - FeatureGroup, - Icon, - LatLngBounds, - LatLngTuple, - markerClusterGroup, - MarkerClusterGroup, - MarkerClusterGroupOptions, Projection -} from 'leaflet'; +import L, { FeatureGroup, Icon, LatLngBounds, LatLngTuple, Projection } from 'leaflet'; import tinycolor from 'tinycolor2'; import 'leaflet-providers'; -import 'leaflet.markercluster/dist/leaflet.markercluster'; +import { MarkerClusterGroup, MarkerClusterGroupOptions } from 'leaflet.markercluster/dist/leaflet.markercluster'; +import '@geoman-io/leaflet-geoman-free'; import { defaultSettings, FormattedData, - MapProviders, MapSettings, MarkerSettings, PolygonSettings, @@ -39,12 +31,10 @@ import { UnitedMapSettings } from './map-models'; import { Marker } from './markers'; -import { Observable, of } from 'rxjs'; +import { forkJoin, Observable, of } from 'rxjs'; import { Polyline } from './polyline'; import { Polygon } from './polygon'; -import { - createTooltip, -} from '@home/components/widget/lib/maps/maps-utils'; +import { createTooltip } from '@home/components/widget/lib/maps/maps-utils'; import { checkLngLat, createLoadingDiv, @@ -54,6 +44,15 @@ import { } from '@home/components/widget/lib/maps/common-maps-utils'; import { WidgetContext } from '@home/models/widget-component.models'; import { deepClone, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils'; +import { TranslateService } from '@ngx-translate/core'; +import { + SelectEntityDialogComponent, + SelectEntityDialogData +} from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component'; +import { MatDialog } from '@angular/material/dialog'; +import { AttributeService } from '@core/http/attribute.service'; +import { EntityId } from '@shared/models/id/entity-id'; +import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; export default abstract class LeafletMap { @@ -78,20 +77,20 @@ export default abstract class LeafletMap { drawRoutes: boolean; showPolygon: boolean; updatePending = false; + editPolygons = false; + selectedEntity: FormattedData; addMarkers: L.Marker[] = []; addPolygons: L.Polygon[] = []; // tslint:disable-next-line:no-string-literal southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180); // tslint:disable-next-line:no-string-literal northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180); - mousePositionOnMap: L.LatLng; - addMarker: L.Control; - addPolygon: L.Control; protected constructor(public ctx: WidgetContext, public $container: HTMLElement, options: UnitedMapSettings) { this.options = options; + this.editPolygons = options.showPolygon && options.editablePolygon; } public initSettings(options: MapSettings) { @@ -102,16 +101,28 @@ export default abstract class LeafletMap { removeOutsideVisibleBounds, animate, chunkedLoading, + spiderfyOnMaxZoom, maxClusterRadius, maxZoom }: MapSettings = options; if (useClusterMarkers) { + // disabled marker cluster icon + (L as any).MarkerCluster = (L as any).MarkerCluster.extend({ + options: { pmIgnore: true, ...L.Icon.prototype.options } + }); const clusteringSettings: MarkerClusterGroupOptions = { - spiderfyOnMaxZoom: false, + spiderfyOnMaxZoom, zoomToBoundsOnClick: zoomOnClick, showCoverageOnHover, removeOutsideVisibleBounds, animate, - chunkedLoading + chunkedLoading, + pmIgnore: true, + spiderLegPolylineOptions: { + pmIgnore: true + }, + polygonOptions: { + pmIgnore: true + } }; if (maxClusterRadius && maxClusterRadius > 0) { clusteringSettings.maxClusterRadius = Math.floor(maxClusterRadius); @@ -119,183 +130,165 @@ export default abstract class LeafletMap { if (maxZoom && maxZoom >= 0 && maxZoom < 19) { clusteringSettings.disableClusteringAtZoom = Math.floor(maxZoom); } - this.markersCluster = markerClusterGroup(clusteringSettings); + this.markersCluster = new MarkerClusterGroup(clusteringSettings); } } - addMarkerControl() { - if (this.options.draggableMarker) { - this.map.on('mousemove', (e: L.LeafletMouseEvent) => { - this.mousePositionOnMap = e.latlng; - }); - const dragListener = (e: L.DragEndEvent) => { - if (e.type === 'dragend' && this.mousePositionOnMap) { - const icon = L.icon({ - iconRetinaUrl: 'marker-icon-2x.png', - iconUrl: 'marker-icon.png', - shadowUrl: 'marker-shadow.png', - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - tooltipAnchor: [16, -28], - shadowSize: [41, 41] - }); - const customLatLng = this.convertToCustomFormat(this.mousePositionOnMap); - this.mousePositionOnMap.lat = customLatLng[this.options.latKeyName]; - this.mousePositionOnMap.lng = customLatLng[this.options.lngKeyName]; - - const newMarker = L.marker(this.mousePositionOnMap, { icon }).addTo(this.map); - this.addMarkers.push(newMarker); - const datasourcesList = document.createElement('div'); - const header = document.createElement('p'); - header.appendChild(document.createTextNode('Select entity:')); - header.setAttribute('style', 'font-size: 14px; margin: 8px 0'); - datasourcesList.appendChild(header); - this.datasources.forEach(ds => { - const dsItem = document.createElement('p'); - dsItem.appendChild(document.createTextNode(ds.entityName)); - dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer'); - dsItem.onclick = () => { - const updatedEnttity = { ...ds, ...customLatLng }; - this.saveMarkerLocation(updatedEnttity).subscribe(() => { - this.map.removeLayer(newMarker); - const markerIndex = this.addMarkers.indexOf(newMarker); - if (markerIndex > -1) { - this.addMarkers.splice(markerIndex, 1); - } - this.deleteMarker(ds.entityName); - this.createMarker(ds.entityName, updatedEnttity, this.datasources, this.options); - }); - }; - datasourcesList.appendChild(dsItem); - }); - datasourcesList.appendChild(document.createElement('br')); - const deleteBtn = document.createElement('a'); - deleteBtn.appendChild(document.createTextNode('Discard changes')); - deleteBtn.onclick = () => { - this.map.removeLayer(newMarker); - const markerIndex = this.addMarkers.indexOf(newMarker); - if (markerIndex > -1) { - this.addMarkers.splice(markerIndex, 1); - } - }; - datasourcesList.appendChild(deleteBtn); - const popup = L.popup(); - popup.setContent(datasourcesList); - newMarker.bindPopup(popup).openPopup(); - } - this.addMarker.setPosition('topright'); - }; - const addMarker = L.Control.extend({ - onAdd() { - const img = L.DomUtil.create('img') as any; - img.src = `assets/add_location.svg`; - img.style.width = '32px'; - img.style.height = '32px'; - img.title = 'Drag and drop to add marker'; - img.onclick = this.dragMarker; - img.draggable = true; - const draggableImg = new L.Draggable(img); - draggableImg.enable(); - draggableImg.on('dragend', dragListener); - return img; - }, - onRemove() { - }, - dragMarker: this.dragMarker - } as any); - const addMarkerControl = (opts) => { - return new addMarker(opts); - }; - this.addMarker = addMarkerControl({ position: 'topright' }).addTo(this.map); + private selectEntityWithoutLocationDialog(shapes: L.PM.SUPPORTED_SHAPES): Observable { + let entities; + switch (shapes) { + case 'Polygon': + case 'Rectangle': + entities = this.datasources.filter(pData => !this.isValidPolygonPosition(pData)); + break; + case 'Marker': + entities = this.datasources.filter(mData => !this.convertPosition(mData)); + break; + default: + return of(null); + } + if (entities.length === 1) { + return of(entities[0]); + } + const dialog = this.ctx.$injector.get(MatDialog); + return dialog.open(SelectEntityDialogComponent, + { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + entities + } + }).afterClosed(); + } + + private selectEntityWithoutLocation(type: string) { + this.selectEntityWithoutLocationDialog(type.substring(2)).subscribe((data) => { + if (data !== null) { + this.selectedEntity = data; + this.toggleDrawMode(type); + } else { + this.map.pm.Toolbar.toggleButton(type, false); } + }); + } + + private toggleDrawMode(type: string) { + this.map.pm.Draw[type].toggle(); } - addPolygonControl() { - if (this.options.showPolygon && this.options.editablePolygon) { - this.map.on('mousemove', (e: L.LeafletMouseEvent) => { - this.mousePositionOnMap = e.latlng; + addEditControl() { + // Customize edit marker + if (this.options.draggableMarker) { + const actions = [{ + text: L.PM.Utils.getTranslation('actions.cancel'), + onClick: () => this.toggleDrawMode('tbMarker') + }]; + + this.map.pm.Toolbar.copyDrawControl('Marker', { + name: 'tbMarker', + afterClick: () => this.selectEntityWithoutLocation('tbMarker'), + disabled: true, + actions + }); + } + + // Customize edit polygon + if (this.editPolygons) { + const rectangleActions = [ + { + text: L.PM.Utils.getTranslation('actions.cancel'), + onClick: () => this.toggleDrawMode('tbRectangle') + } + ]; + + const polygonActions = [ + 'finish' as const, + 'removeLastVertex' as const, + { + text: L.PM.Utils.getTranslation('actions.cancel'), + onClick: () => this.toggleDrawMode('tbPolygon') + } + ]; + + this.map.pm.Toolbar.copyDrawControl('Rectangle', { + name: 'tbRectangle', + afterClick: () => this.selectEntityWithoutLocation('tbRectangle'), + disabled: true, + actions: rectangleActions + }); + + this.map.pm.Toolbar.copyDrawControl('Polygon', { + name: 'tbPolygon', + afterClick: () => this.selectEntityWithoutLocation('tbPolygon'), + disabled: true, + actions: polygonActions + }); + } + + const translateService = this.ctx.$injector.get(TranslateService); + this.map.pm.setLang('en', translateService.instant('widgets.maps'), 'en'); + this.map.pm.addControls({ + position: 'topleft', + drawMarker: false, + drawCircle: false, + drawCircleMarker: false, + drawRectangle: false, + drawPolyline: false, + drawPolygon: false, + editMode: this.editPolygons, + cutPolygon: this.editPolygons, + rotateMode: this.editPolygons }); - const dragListener = (e: L.DragEndEvent) => { - if (e.type === 'dragend') { - const polygonOffset = this.options.provider === MapProviders.image ? 10 : 0.01; - - const convert = this.convertToCustomFormat(this.mousePositionOnMap, polygonOffset); - this.mousePositionOnMap.lat = convert[this.options.latKeyName]; - this.mousePositionOnMap.lng = convert[this.options.lngKeyName]; - - const latlng1 = this.mousePositionOnMap; - const latlng2 = L.latLng(this.mousePositionOnMap.lat, this.mousePositionOnMap.lng + polygonOffset); - const latlng3 = L.latLng(this.mousePositionOnMap.lat - polygonOffset, this.mousePositionOnMap.lng); - const polygonPoints = [latlng1, latlng2, latlng3]; - - const newPolygon = L.polygon(polygonPoints).addTo(this.map); - this.addPolygons.push(newPolygon); - const datasourcesList = document.createElement('div'); - const customLatLng = {[this.options.polygonKeyName]: this.convertToPolygonFormat(polygonPoints)}; - const header = document.createElement('p'); - header.appendChild(document.createTextNode('Select entity:')); - header.setAttribute('style', 'font-size: 14px; margin: 8px 0'); - datasourcesList.appendChild(header); - this.datasources.forEach(ds => { - const dsItem = document.createElement('p'); - dsItem.appendChild(document.createTextNode(ds.entityName)); - dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer'); - dsItem.onclick = () => { - const updatedEnttity = { ...ds, ...customLatLng }; - this.savePolygonLocation(updatedEnttity).subscribe(() => { - this.map.removeLayer(newPolygon); - const polygonIndex = this.addPolygons.indexOf(newPolygon); - if (polygonIndex > -1) { - this.addPolygons.splice(polygonIndex, 1); - } - this.deletePolygon(ds.entityName); - }); - }; - datasourcesList.appendChild(dsItem); + this.map.on('pm:create', (e) => { + if (e.shape === 'tbMarker') { + // @ts-ignore + this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => { + }); + } else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') { + // @ts-ignore + this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(e.layer.getLatLngs()[0])).subscribe(() => { }); - datasourcesList.appendChild(document.createElement('br')); - const deleteBtn = document.createElement('a'); - deleteBtn.appendChild(document.createTextNode('Discard changes')); - deleteBtn.onclick = () => { - this.map.removeLayer(newPolygon); - const polygonIndex = this.addPolygons.indexOf(newPolygon); - if (polygonIndex > -1) { - this.addPolygons.splice(polygonIndex, 1); - } - }; - datasourcesList.appendChild(deleteBtn); - const popup = L.popup(); - popup.setContent(datasourcesList); - newPolygon.bindPopup(popup).openPopup(); } - this.addPolygon.setPosition('topright'); - }; - const addPolygon = L.Control.extend({ - onAdd() { - const img = L.DomUtil.create('img') as any; - img.src = `assets/add_polygon.svg`; - img.style.width = '32px'; - img.style.height = '32px'; - img.title = 'Drag and drop to add Polygon'; - img.onclick = this.dragPolygonVertex; - img.draggable = true; - const draggableImg = new L.Draggable(img); - draggableImg.enable(); - draggableImg.on('dragend', dragListener); - return img; - }, - onRemove() { - }, - dragPolygonVertex: this.dragPolygonVertex - } as any); - const addPolygonControl = (opts) => { - return new addPolygon(opts); - }; - this.addPolygon = addPolygonControl({ position: 'topright' }).addTo(this.map); + // @ts-ignore + e.layer._pmTempLayer = true; + e.layer.remove(); + }); + + this.map.on('pm:cut', (e) => { + // @ts-ignore + e.originalLayer.setLatLngs(e.layer.getLatLngs()); + e.originalLayer.addTo(this.map); + // @ts-ignore + e.originalLayer._pmTempLayer = false; + const iterator = this.polygons.values(); + let result = iterator.next(); + while (!result.done && e.originalLayer !== result.value.leafletPoly) { + result = iterator.next(); + } + // @ts-ignore + e.layer._pmTempLayer = true; + e.layer.remove(); + }); + + this.map.on('pm:remove', (e) => { + if (e.shape === 'Marker') { + const iterator = this.markers.values(); + let result = iterator.next(); + while (!result.done && e.layer !== result.value.leafletMarker) { + result = iterator.next(); + } + this.saveLocation(result.value.data, this.convertToCustomFormat(null)).subscribe(() => {}); + } else if (e.shape === 'Polygon') { + const iterator = this.polygons.values(); + let result = iterator.next(); + while (!result.done && e.layer !== result.value.leafletPoly) { + result = iterator.next(); + } + this.saveLocation(result.value.data, this.convertPolygonToCustomFormat(null)).subscribe(() => {}); + } + }); } - } public setLoading(loading: boolean) { if (this.loading !== loading) { @@ -337,11 +330,10 @@ export default abstract class LeafletMap { if (this.options.disableScrollZooming) { this.map.scrollWheelZoom.disable(); } - if (this.options.draggableMarker) { - this.addMarkerControl(); - } - if (this.options.editablePolygon) { - this.addPolygonControl(); + if (this.options.draggableMarker || this.editPolygons) { + this.addEditControl(); + } else { + this.map.pm.disableDraw(); } if (this.options.useClusterMarkers) { this.map.addLayer(this.markersCluster); @@ -352,12 +344,53 @@ export default abstract class LeafletMap { } } - public saveMarkerLocation(datasource: FormattedData, lat?: number, lng?: number): Observable { - return of(null); - } + private saveLocation(e: FormattedData, values: {[key: string]: any}): Observable { + const attributeService = this.ctx.$injector.get(AttributeService); + const attributes = []; + const timeseries = []; + + const entityId: EntityId = { + entityType: e.$datasource.entityType, + id: e.$datasource.entityId + }; - public savePolygonLocation(datasource: FormattedData, coordinates?: Array<[number, number]>): Observable { - return of(null); + for (const dataKeyName of Object.keys(values)) { + for (const key of e.$datasource.dataKeys) { + if (dataKeyName === key.name) { + const value = { + key: key.name, + value: values[dataKeyName] + }; + if (key.type === DataKeyType.attribute) { + attributes.push(value); + } else if (key.type === DataKeyType.timeseries) { + timeseries.push(value); + } + break; + } + } + } + + const observables: Observable[] = []; + if (timeseries.length) { + observables.push(attributeService.saveEntityTimeseries( + entityId, + LatestTelemetry.LATEST_TELEMETRY, + timeseries + )); + } + if (attributes.length) { + observables.push(attributeService.saveEntityAttributes( + entityId, + AttributeScope.SERVER_SCOPE, + attributes + )); + } + if (observables.length) { + return forkJoin(observables); + } else { + return of(null); + } } createLatLng(lat: number, lng: number): L.LatLng { @@ -441,7 +474,7 @@ export default abstract class LeafletMap { } convertToCustomFormat(position: L.LatLng, offset = 0): object { - position = checkLngLat(position, this.southWest, this.northEast, offset); + position = position ? checkLngLat(position, this.southWest, this.northEast, offset) : {lat: null, lng: null} as L.LatLng; return { [this.options.latKeyName]: position.lat, @@ -455,17 +488,18 @@ export default abstract class LeafletMap { if (point.length) { return this.convertToPolygonFormat(point); } else { - return [point.lat, point.lng]; + const convertPoint = checkLngLat(point, this.southWest, this.northEast); + return [convertPoint.lat, convertPoint.lng]; } }); - } else { - return []; } + return []; } - convertPolygonToCustomFormat(expression: any[][]): object { + convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} { + const coordinate = expression ? this.convertToPolygonFormat(expression) : null; return { - [this.options.polygonKeyName] : this.convertToPolygonFormat(expression) + [this.options.polygonKeyName]: coordinate }; } @@ -484,7 +518,15 @@ export default abstract class LeafletMap { } this.updateMarkers(formattedData, false); this.updateBoundsInternal(); - if (this.options.draggableMarker || this.options.editablePolygon) { + if (this.options.draggableMarker) { + const foundEntityWithoutLocation = formattedData.some(mData => !this.convertPosition(mData)); + this.map.pm.Toolbar.setButtonDisabled('tbMarker', !foundEntityWithoutLocation); + this.datasources = formattedData; + } + if (this.editPolygons) { + const foundEntityWithoutPolygon = formattedData.some(pData => !this.isValidPolygonPosition(pData)); + this.map.pm.Toolbar.setButtonDisabled('tbPolygon', !foundEntityWithoutPolygon); + this.map.pm.Toolbar.setButtonDisabled('tbRectangle', !foundEntityWithoutPolygon); this.datasources = formattedData; } } else { @@ -577,10 +619,10 @@ export default abstract class LeafletMap { } dragMarker = (e, data = {} as FormattedData) => { - if (e.type !== 'dragend') { + if (e === undefined) { return; } - this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) }).subscribe(); + this.saveLocation(data, this.convertToCustomFormat(e.target._latlng)).subscribe(); } private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, @@ -728,11 +770,15 @@ export default abstract class LeafletMap { // Polygon + isValidPolygonPosition(data: FormattedData): boolean { + return data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName]); + } + updatePolygons(polyData: FormattedData[], updateBounds = true) { const keys: string[] = []; this.polygonsData = deepClone(polyData); polyData.forEach((data: FormattedData) => { - if (data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName])) { + if (this.isValidPolygonPosition(data)) { if (isString((data[this.options.polygonKeyName]))) { data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]); } @@ -758,15 +804,14 @@ export default abstract class LeafletMap { } dragPolygonVertex = (e?, data = {} as FormattedData) => { - if (e === undefined || (e.type !== 'editable:vertex:dragend' && e.type !== 'editable:vertex:deleted')) { + if (e === undefined) { return; } - if (this.options.provider !== MapProviders.image) { - for (const key of Object.keys(e.layer._latlngs[0])) { - e.layer._latlngs[0][key] = checkLngLat(e.layer._latlngs[0][key], this.southWest, this.northEast); - } + let coordinates = e.layer.getLatLngs(); + if (coordinates.length === 1) { + coordinates = coordinates[0]; } - this.savePolygonLocation({ ...data, ...this.convertPolygonToCustomFormat(e.layer._latlngs) }).subscribe(); + this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {}); } createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index d9183c1cb6..5b99b792e9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -57,6 +57,7 @@ export type MapSettings = { showCoverageOnHover: boolean, animate: boolean, maxClusterRadius: number, + spiderfyOnMaxZoom: boolean, chunkedLoading: boolean, removeOutsideVisibleBounds: boolean, useCustomProvider: boolean, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 3ad10a0980..eca27d6532 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -14,41 +14,23 @@ /// limitations under the License. /// -import { - defaultSettings, - FormattedData, - hereProviders, - MapProviders, - UnitedMapSettings -} from './map-models'; +import { defaultSettings, hereProviders, MapProviders, UnitedMapSettings } from './map-models'; import LeafletMap from './leaflet-map'; import { commonMapSettingsSchema, mapPolygonSchema, - mapProviderSchema, markerClusteringSettingsSchema, markerClusteringSettingsSchemaLeaflet, routeMapSettingsSchema } from './schemes'; import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; -import { - addCondition, - addGroupInfo, - addToSchema, - initSchema, - mergeSchemes -} from '@core/schema-utils'; +import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { getDefCenterPosition, getProviderSchema, parseFunction, parseWithTranslation } from './common-maps-utils'; import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models'; -import { EntityId } from '@shared/models/id/entity-id'; -import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; -import { AttributeService } from '@core/http/attribute.service'; import { TranslateService } from '@ngx-translate/core'; import { UtilsService } from '@core/services/utils.service'; import { EntityDataPageLink } from '@shared/models/query/query.models'; -import { isDefined } from '@core/utils'; -import { forkJoin, Observable, of } from 'rxjs'; import { providerClass } from '@home/components/widget/lib/maps/providers'; // @dynamic @@ -81,8 +63,6 @@ export class MapWidgetController implements MapWidgetInterface { } parseWithTranslation.setTranslate(this.translate); this.map = new MapClass(this.ctx, $element, this.settings); - this.map.saveMarkerLocation = this.setMarkerLocation; - this.map.savePolygonLocation = this.savePolygonLocation; this.pageLink = { page: 0, pageSize: this.settings.mapPageSize, @@ -178,112 +158,6 @@ export class MapWidgetController implements MapWidgetInterface { }, entityName, null, entityLabel); } - setMarkerLocation = (e: FormattedData, lat?: number, lng?: number) => { - const attributeService = this.ctx.$injector.get(AttributeService); - - const entityId: EntityId = { - entityType: e.$datasource.entityType, - id: e.$datasource.entityId - }; - const attributes = []; - const timeseries = []; - - const latProperties = [this.settings.latKeyName, this.settings.xPosKeyName]; - const lngProperties = [this.settings.lngKeyName, this.settings.yPosKeyName]; - e.$datasource.dataKeys.forEach(key => { - let value; - if (latProperties.includes(key.name)) { - value = { - key: key.name, - value: isDefined(lat) ? lat : e[key.name] - }; - } else if (lngProperties.includes(key.name)) { - value = { - key: key.name, - value: isDefined(lng) ? lng : e[key.name] - }; - } - if (value) { - if (key.type === DataKeyType.attribute) { - attributes.push(value); - } - if (key.type === DataKeyType.timeseries) { - timeseries.push(value); - } - } - }); - const observables: Observable[] = []; - if (timeseries.length) { - observables.push(attributeService.saveEntityTimeseries( - entityId, - LatestTelemetry.LATEST_TELEMETRY, - timeseries - )); - } - if (attributes.length) { - observables.push(attributeService.saveEntityAttributes( - entityId, - AttributeScope.SERVER_SCOPE, - attributes - )); - } - if (observables.length) { - return forkJoin(observables); - } else { - return of(null); - } - } - - savePolygonLocation = (e: FormattedData, coordinates?: Array) => { - const attributeService = this.ctx.$injector.get(AttributeService); - - const entityId: EntityId = { - entityType: e.$datasource.entityType, - id: e.$datasource.entityId - }; - const attributes = []; - const timeseries = []; - - const coordinatesProperties = this.settings.polygonKeyName; - e.$datasource.dataKeys.forEach(key => { - let value; - if (coordinatesProperties === key.name) { - value = { - key: key.name, - value: isDefined(coordinates) ? coordinates : e[key.name] - }; - } - if (value) { - if (key.type === DataKeyType.attribute) { - attributes.push(value); - } - if (key.type === DataKeyType.timeseries) { - timeseries.push(value); - } - } - }); - const observables: Observable[] = []; - if (timeseries.length) { - observables.push(attributeService.saveEntityTimeseries( - entityId, - LatestTelemetry.LATEST_TELEMETRY, - timeseries - )); - } - if (attributes.length) { - observables.push(attributeService.saveEntityAttributes( - entityId, - AttributeScope.SERVER_SCOPE, - attributes - )); - } - if (observables.length) { - return forkJoin(observables); - } else { - return of(null); - } - } - initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings { const functionParams = ['data', 'dsData', 'dsIndex']; this.provider = settings.provider || this.mapProvider; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss index 7abf1423c7..147386685c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss @@ -29,6 +29,10 @@ box-shadow: none; } -.leaflet-container{ +.leaflet-container { background-color: white; } + +.leaflet-buttons-control-button.pm-disabled { + pointer-events: none; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts index cd3f19980f..5550706402 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts @@ -42,9 +42,7 @@ export class Marker { constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings, data?: FormattedData, dataSources?, onDragendListener?) { this.setDataSources(data, dataSources); - this.leafletMarker = L.marker(location, { - draggable: settings.draggableMarker - }); + this.leafletMarker = L.marker(location, {pmIgnore: !settings.draggableMarker}); this.markerOffset = [ isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5, @@ -72,8 +70,8 @@ export class Marker { }); } - if (onDragendListener) { - this.leafletMarker.on('dragend', (e) => onDragendListener(e, this.data)); + if (settings.draggableMarker && onDragendListener) { + this.leafletMarker.on('pm:dragend', (e) => onDragendListener(e, this.data)); } } @@ -199,19 +197,24 @@ export class Marker { createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } { return { - size: [21, 34], - icon: L.icon({ - iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + color.toHex(), - iconSize: [21, 34], - iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]], - popupAnchor: [0, -34], - shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow', - shadowSize: [40, 37], - shadowAnchor: [12, 35] + size: [21, 34], + icon: L.icon({ + iconUrl: this.createColorIconURI(color), + iconSize: [21, 34], + iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]], + popupAnchor: [0, -34], + shadowUrl: 'assets/shadow.png', + shadowSize: [40, 37], + shadowAnchor: [12, 35] }) }; } + createColorIconURI(color: tinycolor.Instance): string { + const svg = ``; + return 'data:image/svg+xml;base64,' + btoa(svg); + } + removeMarker() { /* this.map$.subscribe(map => this.leafletMarker.addTo(map))*/ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts index c7cca2a40b..d87d764d0a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts @@ -17,7 +17,6 @@ import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet'; import { createTooltip } from './maps-utils'; import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils'; -import 'leaflet-editable/src/Leaflet.Editable'; import { FormattedData, PolygonSettings } from './map-models'; export class Polygon { @@ -37,14 +36,12 @@ export class Polygon { color: settings.polygonStrokeColor, weight: settings.polygonStrokeWeight, fillOpacity: settings.polygonOpacity, - opacity: settings.polygonStrokeOpacity + opacity: settings.polygonStrokeOpacity, + pmIgnore: !settings.editablePolygon }).addTo(this.map); - if (settings.editablePolygon) { - this.leafletPoly.enableEdit(this.map); - if (onDragendListener) { - this.leafletPoly.on('editable:vertex:dragend', e => onDragendListener(e, this.data)); - this.leafletPoly.on('editable:vertex:deleted', e => onDragendListener(e, this.data)); - } + + if (settings.editablePolygon && onDragendListener) { + this.leafletPoly.on('pm:edit', (e) => onDragendListener(e, this.data)); } @@ -73,13 +70,7 @@ export class Polygon { updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) { this.data = data; this.dataSources = dataSources; - if (settings.editablePolygon) { - this.leafletPoly.disableEdit(); - } this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]); - if (settings.editablePolygon) { - this.leafletPoly.enableEdit(this.map); - } if (settings.showPolygonTooltip) { this.updateTooltip(this.data); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts index be319ded3a..895dc15763 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts @@ -14,7 +14,8 @@ /// limitations under the License. /// -import L, { PolylineDecoratorOptions } from 'leaflet'; +// @ts-ignore +import L, { PolylineDecorator, PolylineDecoratorOptions, Symbol } from 'leaflet'; import 'leaflet-polylinedecorator'; import { FormattedData, PolylineSettings } from './map-models'; @@ -23,7 +24,7 @@ import { functionValueCalculator } from '@home/components/widget/lib/maps/common export class Polyline { leafletPoly: L.Polyline; - polylineDecorator: L.PolylineDecorator; + polylineDecorator: PolylineDecorator; dataSources: FormattedData[]; data: FormattedData; @@ -36,7 +37,7 @@ export class Polyline { ).addTo(this.map); if (settings.usePolylineDecorator) { - this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); + this.polylineDecorator = new PolylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); } } @@ -47,7 +48,7 @@ export class Polyline { offset: settings.decoratorOffset, endOffset: settings.endDecoratorOffset, repeat: settings.decoratorRepeat, - symbol: L.Symbol[settings.decoratorSymbol]({ + symbol: Symbol[settings.decoratorSymbol]({ pixelSize: settings.decoratorSymbolSize, polygon: false, pathOptions: { @@ -78,7 +79,8 @@ export class Polyline { opacity: functionValueCalculator(settings.useStrokeOpacityFunction, settings.strokeOpacityFunction, [this.data, this.dataSources, this.data.dsIndex], settings.strokeOpacity), weight: functionValueCalculator(settings.useStrokeWeightFunction, settings.strokeWeightFunction, - [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight) + [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight), + pmIgnore: true }; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts index f3369dd46c..00d9353218 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts @@ -38,7 +38,6 @@ export class GoogleMap extends LeafletMap { this.loadGoogle(() => { const map = L.map($container, { attributionControl: false, - editable: !!options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); (L.gridLayer as any).googleMutant({ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts index e15c897c3b..caac9a78b4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts @@ -23,7 +23,6 @@ export class HEREMap extends LeafletMap { constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { super(ctx, $container, options); const map = L.map($container, { - editable: !!options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index 272476ea9e..be427f55cf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -22,7 +22,6 @@ import { filter, map, mergeMap } from 'rxjs/operators'; import { aspectCache, calculateNewPointCoordinate, - checkLngLat, parseFunction } from '@home/components/widget/lib/maps/common-maps-utils'; import { WidgetContext } from '@home/models/widget-component.models'; @@ -221,7 +220,6 @@ export class ImageMap extends LeafletMap { zoom: 1, crs: L.CRS.Simple, attributionControl: false, - editable: !!this.options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }); this.updateBounds(updateImage); @@ -263,7 +261,13 @@ export class ImageMap extends LeafletMap { return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1); } - convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): object { + convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): {[key: string]: any} { + if (!position) { + return { + [this.options.xPosKeyName]: null, + [this.options.yPosKeyName]: null + }; + } const point = this.latLngToPoint(position); const customX = calculateNewPointCoordinate(point.x, width); const customY = calculateNewPointCoordinate(point.y, height); @@ -279,13 +283,9 @@ export class ImageMap extends LeafletMap { point.y = height; } - const customLatLng = checkLngLat(this.pointToLatLng(point.x, point.y), this.southWest, this.northEast, offset); - return { [this.options.xPosKeyName]: customX, - [this.options.yPosKeyName]: customY, - [this.options.latKeyName]: customLatLng.lat, - [this.options.lngKeyName]: customLatLng.lng + [this.options.yPosKeyName]: customY }; } @@ -304,9 +304,10 @@ export class ImageMap extends LeafletMap { } } - convertPolygonToCustomFormat(expression: any[][]): object { + convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} { + const coordinate = expression ? this.convertToPolygonFormat(expression) : null; return { - [this.options.polygonKeyName] : this.convertToPolygonFormat(expression) + [this.options.polygonKeyName]: coordinate }; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts index 61312aab23..01eb04ea40 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts @@ -23,7 +23,6 @@ export class OpenStreetMap extends LeafletMap { constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { super(ctx, $container, options); const map = L.map($container, { - editable: !!options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); let tileLayer; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts index bd34e24331..5e71d92e5d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts @@ -25,7 +25,6 @@ export class TencentMap extends LeafletMap { super(ctx, $container, options); const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; const map = L.map($container, { - editable: !!options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); const txLayer = L.tileLayer(txUrl, { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index 4c7e6e61fa..ff52ece929 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -728,6 +728,11 @@ export const markerClusteringSettingsSchemaLeaflet = type: 'number', default: 80 }, + spiderfyOnMaxZoom: { + title: 'Spiderfy at the max zoom level (to see all cluster markers)', + type: 'boolean', + default: false + }, chunkedLoading: { title: 'Use chunks for adding markers so that the page does not freeze', type: 'boolean', @@ -747,6 +752,7 @@ export const markerClusteringSettingsSchemaLeaflet = 'showCoverageOnHover', 'animate', 'maxClusterRadius', + 'spiderfyOnMaxZoom', 'chunkedLoading', 'removeOutsideVisibleBounds' ] diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index b8b1d193e4..dfa630b3ad 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -100,7 +100,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy addGroupInfo(schema, 'Path Settings'); addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints'])); addGroupInfo(schema, 'Path Points Settings'); - addToSchema(schema, addCondition(mapPolygonSchema, 'model.showPolygon === true', ['showPolygon'])); + const mapPolygonSchemaWithoutEdit = mapPolygonSchema; + delete mapPolygonSchemaWithoutEdit.schema.properties.editablePolygon; + mapPolygonSchemaWithoutEdit.form.splice(mapPolygonSchemaWithoutEdit.form.indexOf('editablePolygon'), 1); + addToSchema(schema, addCondition(mapPolygonSchemaWithoutEdit, 'model.showPolygon === true', ['showPolygon'])); addGroupInfo(schema, 'Polygon Settings'); return schema; } @@ -115,6 +118,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy rotationAngle: 0 }; this.settings = { ...settings, ...this.ctx.settings }; + this.settings.editablePolygon = false; this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor; this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']); diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts index ed9ef23f82..ba692ed122 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts @@ -41,6 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges- import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component'; import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component'; import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component'; +import { SelectEntityDialogComponent } from './lib/maps/dialogs/select-entity-dialog.component'; @NgModule({ declarations: @@ -62,7 +63,8 @@ import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-wi NavigationCardsWidgetComponent, NavigationCardWidgetComponent, QrCodeWidgetComponent, - MarkdownWidgetComponent + MarkdownWidgetComponent, + SelectEntityDialogComponent ], imports: [ CommonModule, diff --git a/ui-ngx/src/assets/add_location.svg b/ui-ngx/src/assets/add_location.svg deleted file mode 100644 index e3150115b7..0000000000 --- a/ui-ngx/src/assets/add_location.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/ui-ngx/src/assets/add_polygon.svg b/ui-ngx/src/assets/add_polygon.svg deleted file mode 100644 index 098f02c128..0000000000 --- a/ui-ngx/src/assets/add_polygon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index bd14f73e27..3ee86c15d6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3238,7 +3238,40 @@ "update-timeseries": "Update timeseries", "value": "Value" }, - "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type" + "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type", + "maps": { + "select-entity": "Select entity", + "select-entity-hint": "Hint: after selection click at the map to set position", + "tooltips": { + "placeMarker": "Click to place marker", + "firstVertex": "Click to place first point", + "continueLine": "Click to continue drawing", + "finishLine": "Click any existing marker to finish", + "finishPoly": "Click first marker to finish and save", + "finishRect": "Click to finish and save", + "startCircle": "Click to place circle center", + "finishCircle": "Click to finish circle", + "placeCircleMarker": "Click to place circle marker" + }, + "actions": { + "finish": "Finish", + "cancel": "Cancel", + "removeLastVertex": "Remove last point" + }, + "buttonTitles": { + "drawMarkerButton": "Create marker", + "drawPolyButton": "Create polygon", + "drawLineButton": "Create Polyline", + "drawCircleButton": "Create Circle", + "drawRectButton": "Create rectangle", + "editButton": "Edit mode", + "dragButton": "Drag-drop mode", + "cutButton": "Cut polygon area", + "deleteButton": "Remove", + "drawCircleMarkerButton": "Create circle marker", + "rotateButton": "Rotate polygon" + } + } }, "icon": { "icon": "Icon", diff --git a/ui-ngx/src/assets/shadow.png b/ui-ngx/src/assets/shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..fc2f271799dbf1ec2055dd532952cd9c1adff6e2 GIT binary patch literal 712 zcmV;(0yq7MP)DPwCqqps>CHM?|!y z5@-i@Vt4v!5yADje^sQdo^bOC^;Sfmh}zGz6)FojnqV^tv={r*cILGSt(t3BBS9AO z0W0~ti0G(R)AS8Eg+17hgE)}3J;AD7))r+^6)BvvvVn@`S<%g901LQ79X2D<-iwOS zvn-;wB+~j_L~*HeL9c+71lg64dqos?C_f1*_@dP$AMhSuSG&1az$t7I9XgX>+xmd3 z;~ie(C0^ipo?BJD0*-0TyU7IZR&T4RCZhEa57M6DW4A@U02VW9QEQkMgSB{r{7KCO z`-)cycOOsjCim&8UI3Rx5r4w0Nby#!L0r6VJJm?AH+Y2Gc#?a}Ya7OE1thxbvlt7T zL_KcFIbmU zqDb49JZ^`piO#%=OSmf@YE3E&SWCFN=;{r5zKO>;hx4ND2BLmG7ACZ6u_5a74$k7D zXn=vKAHcd+Cy(JK&fuB>q_k6I0V|?G4vTNV>o_Ig>VriKl?80#D2|A+a~hWi4b`r) ufX8rL)ZHmu7&y@ybwZ@`IIX7+?Kac^0000 Date: Fri, 26 Nov 2021 12:41:04 +0200 Subject: [PATCH 263/303] UI: Fixed open dashboard state in separate dialog showed a blank dialog --- .../src/app/modules/home/components/widget/widget.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 8aaf9eb603..05d8686d46 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -1419,6 +1419,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI height: dialogHeight } }); + this.cd.markForCheck(); } private elementClick($event: Event) { From eda4e0f76181b9282d71256b42fa1a51cc614ab0 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 26 Nov 2021 13:47:07 +0200 Subject: [PATCH 264/303] Fixed right layout and state name propagation in mobile mode, skip popover/dialog dashboard changes. --- .../dashboard-page.component.ts | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 534d22834a..37ef5e0429 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -345,24 +345,26 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.runChangeDetection(); } )); - this.rxSubscriptions.push(this.route.queryParamMap.subscribe( - (paramMap) => { - if (paramMap.has('reload')) { - this.dashboardCtx.aliasController.updateAliases(); - setTimeout(() => { - this.mobileService.handleDashboardStateName(this.dashboardCtx.stateController.getCurrentStateName()); - this.mobileService.onDashboardLoaded(this.layouts.right.show, this.isRightLayoutOpened); - }); + if (this.syncStateWithQueryParam) { + this.rxSubscriptions.push(this.route.queryParamMap.subscribe( + (paramMap) => { + if (paramMap.has('reload')) { + this.dashboardCtx.aliasController.updateAliases(); + setTimeout(() => { + this.mobileService.handleDashboardStateName(this.dashboardCtx.stateController.getCurrentStateName()); + this.mobileService.onDashboardLoaded(this.layouts.right.show, this.isRightLayoutOpened); + }); + } } - } - )); + )); + } this.rxSubscriptions.push(this.breakpointObserver .observe(MediaBreakpoints['gt-sm']) .subscribe((state: BreakpointState) => { this.isMobile = !state.matches; } )); - if (this.isMobileApp) { + if (this.isMobileApp && this.syncStateWithQueryParam) { this.mobileService.registerToggleLayoutFunction(() => { setTimeout(() => { this.toggleLayouts(); @@ -464,7 +466,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC } ngOnDestroy(): void { - if (this.isMobileApp) { + if (this.isMobileApp && this.syncStateWithQueryParam) { this.mobileService.unregisterToggleLayoutFunction(); } this.rxSubscriptions.forEach((subscription) => { From 79251adb3ae65e0dab93d8cd56533e561ac0caa1 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 26 Nov 2021 16:01:21 +0200 Subject: [PATCH 265/303] UI: Revert code for backward-compatible after having updated editors in maps widgets --- .../components/widget/lib/maps/leaflet-map.ts | 57 +----------- .../components/widget/lib/maps/map-widget2.ts | 93 ++++++++++++++++++- ui-ngx/yarn.lock | 2 +- 3 files changed, 97 insertions(+), 55 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 03249a5307..5db9db2e9e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -31,7 +31,7 @@ import { UnitedMapSettings } from './map-models'; import { Marker } from './markers'; -import { forkJoin, Observable, of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { Polyline } from './polyline'; import { Polygon } from './polygon'; import { createTooltip } from '@home/components/widget/lib/maps/maps-utils'; @@ -50,9 +50,6 @@ import { SelectEntityDialogData } from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component'; import { MatDialog } from '@angular/material/dialog'; -import { AttributeService } from '@core/http/attribute.service'; -import { EntityId } from '@shared/models/id/entity-id'; -import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; export default abstract class LeafletMap { @@ -85,6 +82,9 @@ export default abstract class LeafletMap { southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180); // tslint:disable-next-line:no-string-literal northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180); + saveLocation: (e: FormattedData, values: {[key: string]: any}) => Observable; + saveMarkerLocation: (e: FormattedData, lat?: number, lng?: number) => Observable; + savePolygonLocation: (e: FormattedData, coordinates?: Array) => Observable; protected constructor(public ctx: WidgetContext, public $container: HTMLElement, @@ -344,55 +344,6 @@ export default abstract class LeafletMap { } } - private saveLocation(e: FormattedData, values: {[key: string]: any}): Observable { - const attributeService = this.ctx.$injector.get(AttributeService); - const attributes = []; - const timeseries = []; - - const entityId: EntityId = { - entityType: e.$datasource.entityType, - id: e.$datasource.entityId - }; - - for (const dataKeyName of Object.keys(values)) { - for (const key of e.$datasource.dataKeys) { - if (dataKeyName === key.name) { - const value = { - key: key.name, - value: values[dataKeyName] - }; - if (key.type === DataKeyType.attribute) { - attributes.push(value); - } else if (key.type === DataKeyType.timeseries) { - timeseries.push(value); - } - break; - } - } - } - - const observables: Observable[] = []; - if (timeseries.length) { - observables.push(attributeService.saveEntityTimeseries( - entityId, - LatestTelemetry.LATEST_TELEMETRY, - timeseries - )); - } - if (attributes.length) { - observables.push(attributeService.saveEntityAttributes( - entityId, - AttributeScope.SERVER_SCOPE, - attributes - )); - } - if (observables.length) { - return forkJoin(observables); - } else { - return of(null); - } - } - createLatLng(lat: number, lng: number): L.LatLng { return L.latLng(lat, lng); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index eca27d6532..21c576eeb1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { defaultSettings, hereProviders, MapProviders, UnitedMapSettings } from './map-models'; +import { defaultSettings, FormattedData, hereProviders, MapProviders, UnitedMapSettings } from './map-models'; import LeafletMap from './leaflet-map'; import { commonMapSettingsSchema, @@ -32,6 +32,12 @@ import { TranslateService } from '@ngx-translate/core'; import { UtilsService } from '@core/services/utils.service'; import { EntityDataPageLink } from '@shared/models/query/query.models'; import { providerClass } from '@home/components/widget/lib/maps/providers'; +import { isDefined } from '@core/utils'; +import L from 'leaflet'; +import { forkJoin, Observable, of } from 'rxjs'; +import { AttributeService } from '@core/http/attribute.service'; +import { EntityId } from '@shared/models/id/entity-id'; +import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; // @dynamic export class MapWidgetController implements MapWidgetInterface { @@ -63,6 +69,10 @@ export class MapWidgetController implements MapWidgetInterface { } parseWithTranslation.setTranslate(this.translate); this.map = new MapClass(this.ctx, $element, this.settings); + (this.ctx as any).mapInstance = this.map; + this.map.saveMarkerLocation = this.setMarkerLocation; + this.map.savePolygonLocation = this.savePolygonLocation; + this.map.saveLocation = this.saveLocation; this.pageLink = { page: 0, pageSize: this.settings.mapPageSize, @@ -158,6 +168,86 @@ export class MapWidgetController implements MapWidgetInterface { }, entityName, null, entityLabel); } + setMarkerLocation(e: FormattedData, lat?: number, lng?: number) { + let markerValue; + if (isDefined(lat) && isDefined(lng)) { + const point = lat != null && lng !== null ? L.latLng(lat, lng) : null; + markerValue = this.map.convertToCustomFormat(point); + } else if (this.settings.mapProvider !== MapProviders.image) { + markerValue = { + [this.settings.latKeyName]: e[this.settings.latKeyName], + [this.settings.lngKeyName]: e[this.settings.lngKeyName], + }; + } else { + markerValue = { + [this.settings.xPosKeyName]: e[this.settings.xPosKeyName], + [this.settings.yPosKeyName]: e[this.settings.yPosKeyName], + }; + } + return this.saveLocation(e, markerValue); + } + + savePolygonLocation(e: FormattedData, coordinates?: Array) { + let polygonValue; + if (isDefined(coordinates)) { + polygonValue = this.map.convertToPolygonFormat(coordinates); + } else { + polygonValue = { + [this.settings.polygonKeyName]: e[this.settings.polygonKeyName] + }; + } + return this.saveLocation(e, polygonValue); + } + + saveLocation(e: FormattedData, values: {[key: string]: any}): Observable { + const attributeService = this.ctx.$injector.get(AttributeService); + const attributes = []; + const timeseries = []; + + const entityId: EntityId = { + entityType: e.$datasource.entityType, + id: e.$datasource.entityId + }; + + for (const dataKeyName of Object.keys(values)) { + for (const key of e.$datasource.dataKeys) { + if (dataKeyName === key.name) { + const value = { + key: key.name, + value: values[dataKeyName] + }; + if (key.type === DataKeyType.attribute) { + attributes.push(value); + } else if (key.type === DataKeyType.timeseries) { + timeseries.push(value); + } + break; + } + } + } + + const observables: Observable[] = []; + if (timeseries.length) { + observables.push(attributeService.saveEntityTimeseries( + entityId, + LatestTelemetry.LATEST_TELEMETRY, + timeseries + )); + } + if (attributes.length) { + observables.push(attributeService.saveEntityAttributes( + entityId, + AttributeScope.SERVER_SCOPE, + attributes + )); + } + if (observables.length) { + return forkJoin(observables); + } else { + return of(null); + } + } + initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings { const functionParams = ['data', 'dsData', 'dsIndex']; this.provider = settings.provider || this.mapProvider; @@ -209,6 +299,7 @@ export class MapWidgetController implements MapWidgetInterface { } destroy() { + (this.ctx as any).mapInstance = null; if (this.map) { this.map.remove(); } diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 046e100cd1..36eb458108 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -6444,7 +6444,7 @@ leaflet-rotatedmarker@^0.2.0: resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277" integrity sha1-RGf0n5jRv9VpWb2cZwUgPdJgEnc= -leaflet.gridlayer.googlemutant@0.13.4: +leaflet.gridlayer.googlemutant@^0.13.4: version "0.13.4" resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.13.4.tgz#0add37d240c70c999e1f1d341208e6fea2372c40" integrity sha512-oC6xUSFJ9HP4WIupXakgiYckdBHuHQeSaxTXsVlcvcpfsuYoJ/HFIrz1bmK4Qr/qKO4fY1MDM6AoewU7Bph8ZQ== From bdb7d0905d36927dfcf77a7ecb1b7192bc9f5cb2 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 29 Nov 2021 11:42:41 +0200 Subject: [PATCH 266/303] UI: Fixed incorrect URL for default marker icon in maps widget --- .../app/modules/home/components/widget/lib/maps/leaflet-map.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 5db9db2e9e..db62775c40 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -91,6 +91,7 @@ export default abstract class LeafletMap { options: UnitedMapSettings) { this.options = options; this.editPolygons = options.showPolygon && options.editablePolygon; + L.Icon.Default.imagePath = '/'; } public initSettings(options: MapSettings) { From 4f342b596155496012dd6db39e399ae4b6885f45 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 29 Nov 2021 12:00:34 +0200 Subject: [PATCH 267/303] UI: Fixed widgets maps backward compatibility for save location --- .../modules/home/components/widget/lib/maps/map-widget2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 21c576eeb1..a2385b2877 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -70,9 +70,9 @@ export class MapWidgetController implements MapWidgetInterface { parseWithTranslation.setTranslate(this.translate); this.map = new MapClass(this.ctx, $element, this.settings); (this.ctx as any).mapInstance = this.map; - this.map.saveMarkerLocation = this.setMarkerLocation; - this.map.savePolygonLocation = this.savePolygonLocation; - this.map.saveLocation = this.saveLocation; + this.map.saveMarkerLocation = this.setMarkerLocation.bind(this); + this.map.savePolygonLocation = this.savePolygonLocation.bind(this); + this.map.saveLocation = this.saveLocation.bind(this); this.pageLink = { page: 0, pageSize: this.settings.mapPageSize, From 1298f6b13047627e9199e2812ef5b7221fba1910 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 29 Nov 2021 16:51:43 +0200 Subject: [PATCH 268/303] Fix delete attributes cluster notification --- .../DefaultSubscriptionManagerService.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java index 15cf6f1a17..018d80f013 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java @@ -222,7 +222,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } } return subscriptionUpdate; - }); + }, true); if (entityId.getEntityType() == EntityType.DEVICE) { updateDeviceInactivityTimeout(tenantId, entityId, ts); } @@ -256,7 +256,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } } return subscriptionUpdate; - }); + }, true); if (entityId.getEntityType() == EntityType.DEVICE) { if (TbAttributeSubscriptionScope.SERVER_SCOPE.name().equalsIgnoreCase(scope)) { updateDeviceInactivityTimeout(tenantId, entityId, attributes); @@ -333,14 +333,15 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } } return subscriptionUpdate; - }); + }, false); callback.onSuccess(); } private void onLocalTelemetrySubUpdate(EntityId entityId, Function castFunction, Predicate filterFunction, - Function> processFunction) { + Function> processFunction, + boolean ignoreEmptyUpdates) { Set entitySubscriptions = subscriptionsByEntityId.get(entityId); if (entitySubscriptions != null) { entitySubscriptions.stream().map(castFunction).filter(Objects::nonNull).filter(filterFunction).forEach(s -> { @@ -351,7 +352,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene localSubscriptionService.onSubscriptionUpdate(s.getSessionId(), update, TbCallback.EMPTY); } else { TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId()); - toCoreNotificationsProducer.send(tpi, toProto(s, subscriptionUpdate), null); + toCoreNotificationsProducer.send(tpi, toProto(s, subscriptionUpdate, ignoreEmptyUpdates), null); } } }); @@ -467,6 +468,10 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } private TbProtoQueueMsg toProto(TbSubscription subscription, List updates) { + return toProto(subscription, updates, true); + } + + private TbProtoQueueMsg toProto(TbSubscription subscription, List updates, boolean ignoreEmptyUpdates) { TbSubscriptionUpdateProto.Builder builder = TbSubscriptionUpdateProto.newBuilder(); builder.setSessionId(subscription.getSessionId()); @@ -494,7 +499,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene dataBuilder.addValue(strVal); } } - if (hasData) { + if (!ignoreEmptyUpdates || hasData) { builder.addData(dataBuilder.build()); } }); From b04949c62cff2ae1960bb35657fd8fa6368addda Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 29 Nov 2021 19:20:08 +0200 Subject: [PATCH 269/303] Null values support for subscription update values proto --- .../subscription/DefaultSubscriptionManagerService.java | 6 ++++-- .../server/service/subscription/TbSubscriptionUtils.java | 8 +++++--- common/cluster-api/src/main/proto/queue.proto | 9 +++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java index 018d80f013..6e5ca1669f 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java @@ -492,12 +492,14 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene boolean hasData = false; for (Object v : value) { Object[] array = (Object[]) v; - dataBuilder.addTs((long) array[0]); + TbSubscriptionUpdateTsValue.Builder tsValueBuilder = TbSubscriptionUpdateTsValue.newBuilder(); + tsValueBuilder.setTs((long) array[0]); String strVal = (String) array[1]; if (strVal != null) { hasData = true; - dataBuilder.addValue(strVal); + tsValueBuilder.setValue(strVal); } + dataBuilder.addTsValue(tsValueBuilder.build()); } if (!ignoreEmptyUpdates || hasData) { builder.addData(dataBuilder.build()); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java index 978d7aaac3..25b67d3a06 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java @@ -42,6 +42,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionCloseP import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionKetStateProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateProto; +import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateTsValue; import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesSubscriptionProto; import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; @@ -171,10 +172,11 @@ public class TbSubscriptionUtils { Map> data = new TreeMap<>(); proto.getDataList().forEach(v -> { List values = data.computeIfAbsent(v.getKey(), k -> new ArrayList<>()); - for (int i = 0; i < v.getTsCount(); i++) { + for (int i = 0; i < v.getTsValueCount(); i++) { Object[] value = new Object[2]; - value[0] = v.getTs(i); - value[1] = v.getValue(i); + TbSubscriptionUpdateTsValue tsValue = v.getTsValue(i); + value[0] = tsValue.getTs(); + value[1] = tsValue.hasValue() ? tsValue.getValue() : null; values.add(value); } }); diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 5b220974ef..dca92c1c7a 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -14,6 +14,7 @@ * limitations under the License. */ syntax = "proto3"; + package transport; option java_package = "org.thingsboard.server.gen.transport"; @@ -581,8 +582,12 @@ message TbSubscriptionKetStateProto { message TbSubscriptionUpdateValueListProto { string key = 1; - repeated int64 ts = 2; - repeated string value = 3; + repeated TbSubscriptionUpdateTsValue tsValue = 2; +} + +message TbSubscriptionUpdateTsValue { + int64 ts = 1; + optional string value = 2; } /** From 4ac52b10d8d041611d62ee38fb69c4e45b4f5350 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 29 Nov 2021 19:43:26 +0200 Subject: [PATCH 270/303] fixed sessions updating on lwm2m transport start --- .../lwm2m/server/DefaultLwM2mTransportService.java | 7 ++----- .../lwm2m/server/client/LwM2mClientContextImpl.java | 7 +++++-- .../lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java | 6 ++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index 15aeac095c..147e20c02b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.server; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; @@ -29,6 +28,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; +import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; @@ -37,10 +37,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; -import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.security.PrivateKey; -import java.security.PublicKey; import java.security.cert.X509Certificate; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; @@ -71,7 +68,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { private LeshanServer server; - @PostConstruct + @AfterStartUp public void init() { this.server = getLhServer(); /* diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index da304821da..823f16a99a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -22,7 +22,10 @@ import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Lazy; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.data.PowerMode; @@ -33,7 +36,6 @@ import org.thingsboard.server.common.transport.TransportDeviceProfileCache; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; @@ -88,7 +90,8 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private final Map profiles = new ConcurrentHashMap<>(); - @AfterStartUp + @EventListener(ApplicationReadyEvent.class) + @Order(Integer.MAX_VALUE - 1) public void init() { String nodeId = context.getNodeId(); Set fetchedClients = clientStore.getAll(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 161ca3d2f1..a728a0b6e0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -87,6 +87,12 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return; } LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); + + if (client == null) { + log.warn("Missing client for session: [{}]", sessionInfo); + return; + } + if (client.getRegistration() == null) { this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); return; From 8232244b6e5436d724c38b7eecd7969b172f47df Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:40:11 +0200 Subject: [PATCH 271/303] Update node and yarn versions --- ui-ngx/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index d071908001..328a63f949 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -56,8 +56,8 @@ install-node-and-yarn - v12.16.1 - v1.22.4 + v16.13.0 + v1.22.17 From 6578c5eaeb704943f1b7ca5a35840c28837f6640 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:41:46 +0200 Subject: [PATCH 272/303] Update webpack --- ui-ngx/package.json | 2 +- ui-ngx/yarn.lock | 343 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 310 insertions(+), 35 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 653711a8c1..672af523b0 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -143,7 +143,7 @@ "ts-node": "^9.0.0", "tslint": "~6.1.3", "typescript": "~4.0.3", - "webpack": "^4.46.0" + "webpack": "^5.64.4" }, "resolutions": { "lodash": "~4.17.21" diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 36eb458108..c749b240a5 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -1881,6 +1881,27 @@ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.10.tgz#61cc8469849e5bcdd0c7044122265c39cec10cf4" integrity sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ== +"@types/eslint-scope@^3.7.0": + version "3.7.1" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e" + integrity sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.2.0.tgz#afd0519223c29c347087542cbaee2fedc0873b16" + integrity sha512-74hbvsnc+7TEDa1z5YLSe4/q8hGYB3USNvCuzHUJrjPV6hXaq8IXcngCrHkuvFt0+8rFz7xYXrHgNayIX0UZvQ== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + "@types/flot@^0.0.31": version "0.0.31" resolved "https://registry.yarnpkg.com/@types/flot/-/flot-0.0.31.tgz#0daca37c6c855b69a0a7e2e37dd0f84b3db8c8c1" @@ -1947,6 +1968,11 @@ resolved "https://registry.yarnpkg.com/@types/js-beautify/-/js-beautify-1.13.1.tgz#d4739266c5dcad561226cd1ec5407fa0542d863d" integrity sha512-F3YCoZS//n74Wu+hxoVrxX1H8qaWo+WAgQ+ObmFH4ZFwI0fIwiJTW7pvkCRShw8ST7+ej7sB68K+ZHAZgK4S4Q== +"@types/json-schema@*", "@types/json-schema@^7.0.8": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + "@types/json-schema@^7.0.5": version "7.0.6" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" @@ -2138,6 +2164,14 @@ "@types/source-list-map" "*" source-map "^0.6.1" +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -2147,16 +2181,31 @@ "@webassemblyjs/helper-wasm-bytecode" "1.9.0" "@webassemblyjs/wast-parser" "1.9.0" +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + "@webassemblyjs/floating-point-hex-parser@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + "@webassemblyjs/helper-api-error@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + "@webassemblyjs/helper-buffer@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" @@ -2181,11 +2230,35 @@ dependencies: "@webassemblyjs/ast" "1.9.0" +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + "@webassemblyjs/helper-wasm-bytecode@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/helper-wasm-section@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" @@ -2196,6 +2269,13 @@ "@webassemblyjs/helper-wasm-bytecode" "1.9.0" "@webassemblyjs/wasm-gen" "1.9.0" +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + "@webassemblyjs/ieee754@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" @@ -2203,6 +2283,13 @@ dependencies: "@xtuc/ieee754" "^1.2.0" +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + "@webassemblyjs/leb128@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" @@ -2210,11 +2297,30 @@ dependencies: "@xtuc/long" "4.2.2" +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + "@webassemblyjs/utf8@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + "@webassemblyjs/wasm-edit@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" @@ -2229,6 +2335,17 @@ "@webassemblyjs/wasm-parser" "1.9.0" "@webassemblyjs/wast-printer" "1.9.0" +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/wasm-gen@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" @@ -2240,6 +2357,16 @@ "@webassemblyjs/leb128" "1.9.0" "@webassemblyjs/utf8" "1.9.0" +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wasm-opt@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" @@ -2250,6 +2377,18 @@ "@webassemblyjs/wasm-gen" "1.9.0" "@webassemblyjs/wasm-parser" "1.9.0" +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/wasm-parser@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" @@ -2274,6 +2413,14 @@ "@webassemblyjs/helper-fsm" "1.9.0" "@xtuc/long" "4.2.2" +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + "@webassemblyjs/wast-printer@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" @@ -2321,11 +2468,21 @@ ace-builds@^1.4.12, ace-builds@^1.4.6: resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.12.tgz#888efa386e36f4345f40b5233fcc4fe4c588fae7" integrity sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg== +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + acorn@^6.4.1: version "6.4.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +acorn@^8.4.1: + version "8.6.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" + integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== + add-dom-event-listener@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310" @@ -4417,14 +4574,13 @@ enhanced-resolve@^4.3.0: memory-fs "^0.5.0" tapable "^1.0.0" -enhanced-resolve@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" - integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== +enhanced-resolve@^5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" + integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" + graceful-fs "^4.2.4" + tapable "^2.2.0" ent@~2.2.0: version "2.2.0" @@ -4500,6 +4656,11 @@ es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -4541,6 +4702,14 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -4554,7 +4723,7 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esrecurse@^4.1.0: +esrecurse@^4.1.0, esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== @@ -4596,6 +4765,11 @@ events@^3.0.0: resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + eventsource@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" @@ -5100,6 +5274,11 @@ glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + glob@7.1.6, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -6071,6 +6250,15 @@ jest-worker@26.6.2, jest-worker@^26.5.0: merge-stream "^2.0.0" supports-color "^7.0.0" +jest-worker@^27.0.6: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.0.tgz#fa10dddc611cbb47a4153543dd16a0c7e7fd745c" + integrity sha512-4WuKcUxtzxBoKOUFbt1MtTY9fJwPVD4aN/4Cgxee7OLetPZn5as2bjfZz98XSf2Zq1JFfhqPZpS+43BmWXKgCA== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jquery.terminal@^2.24.0: version "2.24.0" resolved "https://registry.yarnpkg.com/jquery.terminal/-/jquery.terminal-2.24.0.tgz#779a92b4478ac7542e7adaf5e17f4d4d92fd622c" @@ -6510,6 +6698,11 @@ loader-runner@^2.4.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== +loader-runner@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" + integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== + loader-utils@2.0.0, loader-utils@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" @@ -6818,6 +7011,11 @@ mime-db@1.44.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== +mime-db@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + "mime-db@>= 1.43.0 < 2": version "1.45.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" @@ -6830,6 +7028,13 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.44.0" +mime-types@^2.1.27: + version "2.1.34" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + dependencies: + mime-db "1.51.0" + mime@1.6.0, mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -9079,6 +9284,15 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" +schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + screenfull@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.1.0.tgz#85c13c70f4ead4c1b8a935c70010dfdcd2c0e5c8" @@ -9192,6 +9406,13 @@ serialize-javascript@^5.0.1: dependencies: randombytes "^2.1.0" +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + serve-index@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" @@ -9460,6 +9681,14 @@ source-map-support@~0.4.0: dependencies: source-map "^0.5.6" +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -9800,6 +10029,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + svgo@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.3.0.tgz#6b3af81d0cbd1e19c83f5f63cec2cb98c70b5373" @@ -9833,6 +10069,11 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tapable@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + tapable@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" @@ -9892,6 +10133,17 @@ terser-webpack-plugin@^1.4.3: webpack-sources "^1.4.0" worker-farm "^1.7.0" +terser-webpack-plugin@^5.1.3: + version "5.2.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz#ce65b9880a0c36872555c4874f45bbdb02ee32c9" + integrity sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g== + dependencies: + jest-worker "^27.0.6" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.2" + terser@5.5.1: version "5.5.1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" @@ -9919,6 +10171,15 @@ terser@^5.3.4: source-map "~0.7.2" source-map-support "~0.5.19" +terser@^5.7.2: + version "5.10.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" + integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.20" + text-table@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -10412,6 +10673,14 @@ watchpack@^1.7.4: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.0" +watchpack@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.0.tgz#a41bca3da6afaff31e92a433f4c856a0c25ea0c4" + integrity sha512-MnN0Q1OsvB/GGHETrFeZPQaOelWh/7O+EiFlj8sM9GPjtQkis7k01aAxrg/18kTfoIVcLL+haEVFlXDaSRwKRw== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" @@ -10533,6 +10802,11 @@ webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack- source-list-map "^2.0.0" source-map "~0.6.1" +webpack-sources@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" + integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw== + webpack-subresource-integrity@1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.5.2.tgz#e40b6578d3072e2d24104975249c52c66e9a743e" @@ -10569,34 +10843,35 @@ webpack@4.44.2: watchpack "^1.7.4" webpack-sources "^1.4.1" -webpack@^4.46.0: - version "4.46.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" - integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" +webpack@^5.64.4: + version "5.64.4" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.64.4.tgz#e1454b6a13009f57cc2c78e08416cd674622937b" + integrity sha512-LWhqfKjCLoYJLKJY8wk2C3h77i8VyHowG3qYNZiIqD6D0ZS40439S/KVuc/PY48jp2yQmy0mhMknq8cys4jFMw== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" + enhanced-resolve "^5.8.3" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.4" json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.3.0" + webpack-sources "^3.2.2" websocket-driver@>=0.5.1, websocket-driver@^0.7.4: version "0.7.4" From ad8ffd6734612f204eeb6196e72d37bf73bd2491 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:44:19 +0200 Subject: [PATCH 273/303] Update webpack and ngrx --- ui-ngx/package.json | 8 ++++---- ui-ngx/yarn.lock | 31 ++++++++++++++++++------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 672af523b0..ba60fac028 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -34,9 +34,9 @@ "@material-ui/core": "^4.11.4", "@material-ui/icons": "^4.11.2", "@material-ui/pickers": "^3.3.10", - "@ngrx/effects": "^10.1.2", - "@ngrx/store": "^10.1.2", - "@ngrx/store-devtools": "^10.1.2", + "@ngrx/effects": "^12.5.1", + "@ngrx/store": "^12.5.1", + "@ngrx/store-devtools": "^12.5.1", "@ngx-translate/core": "^13.0.0", "@ngx-translate/http-loader": "^6.0.0", "ace-builds": "^1.4.12", @@ -105,7 +105,7 @@ "@angular/cli": "^11.2.13", "@angular/compiler-cli": "^11.2.14", "@angular/language-service": "^11.2.14", - "@ngtools/webpack": "~11.2.13", + "@ngtools/webpack": "~12.2.13", "@types/canvas-gauges": "^2.1.2", "@types/flot": "^0.0.31", "@types/jasmine": "~3.7.4", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index c749b240a5..5e88917fd1 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -1545,28 +1545,28 @@ prop-types "^15.7.2" react-is "^16.8.0 || ^17.0.0" -"@ngrx/effects@^10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-10.1.2.tgz#f1c9daa2e3e13aeb6af272cb52f6dff73d364d68" - integrity sha512-6pX6FEzLlqdbtFVMbCvscsaL6QC/L95e72JKj76Xz+8V77UTlpVsxWyMo7YU9pM4EXNpBGmOpMs2xKjfBfK05Q== +"@ngrx/effects@^12.5.1": + version "12.5.1" + resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-12.5.1.tgz#acd0ff86d8db514e47337508dde83cc98f7a3416" + integrity sha512-fVNGIIntYLRWW1XWe0os2XOv03L22S4WTkX0OPZ9O6ztwuaNq0yzxWN7UeAC6H385F+g0k76KwRV78zHyP0bfQ== dependencies: tslib "^2.0.0" -"@ngrx/store-devtools@^10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-10.1.2.tgz#1dba8c84df4b56a2b15d6abc01c3c378d1518830" - integrity sha512-HE681GuZ+lRgSXpgt7y7LKzsfu/+Tgy9yPZpaitvkhg+eCIjnN5Uvs1rWqETHYWnsKliW25yoqFUAVw+xb7hug== +"@ngrx/store-devtools@^12.5.1": + version "12.5.1" + resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-12.5.1.tgz#75f8ef9a4bf4a40d5343ff437651f0f3092914b5" + integrity sha512-SXMxVO3KzQUfB9G20gdNT5t/RcbtbaUySXLuH+b69z/eb34wH9AOYifdSdcEi8oqPjDrWYBq6a8Uh+yDHf9IfA== dependencies: tslib "^2.0.0" -"@ngrx/store@^10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-10.1.2.tgz#a41aee81ea7b7e4a9f927be560e6024830211efb" - integrity sha512-FUjN786ch4Qt9WgJ78ef7Yquq3mPCekgcWgZrs4ycZw1f+KdfTHLTk1bGDtO8A8CzOya5yTT7KhxbdVjbOS5ng== +"@ngrx/store@^12.5.1": + version "12.5.1" + resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-12.5.1.tgz#a7c21d7df1d017d2cb7e77804b210cc14bcf8786" + integrity sha512-NLVkHLVeZc7IboXSDZlFoq1QrupmwYTYKRHS6se7ZasAv/lrIjHWsVVdICKSVRBsHZYu3+dmCXmu+YgulP7iHw== dependencies: tslib "^2.0.0" -"@ngtools/webpack@11.2.13", "@ngtools/webpack@~11.2.13": +"@ngtools/webpack@11.2.13": version "11.2.13" resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-11.2.13.tgz#dbd77deb37ab57fd98678bd637fe87693fd71f4f" integrity sha512-Wbv1zjLaS1zXcJ1wryYc6vhKWq8r/+ZrdN5SlRIf3xf7fwuTymbvL41SndUibssXir6s4vePYqZL241nkThx9g== @@ -1575,6 +1575,11 @@ enhanced-resolve "5.7.0" webpack-sources "2.2.0" +"@ngtools/webpack@~12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.2.13.tgz#44d711edfa39d175a2d655aa5c6f9968dfedcc35" + integrity sha512-krAwMyRqOaC1S0+IxAFid9F6A6ABip2DJ0tgCx26X+1Vw/d1GKtV9ZqDJFizMf5k1ywl9aBlhOazWpq5d6i+gw== + "@ngx-translate/core@^13.0.0": version "13.0.0" resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-13.0.0.tgz#60547cb8a0845a2a0abfde6b0bf5ec6516a63fd6" From 0dfc060fdfb4498ecc7017556a4b741a88b2fe67 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:46:42 +0200 Subject: [PATCH 274/303] Update deps versions --- ui-ngx/package.json | 2 +- ui-ngx/yarn.lock | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index ba60fac028..08ef9ad473 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -41,7 +41,7 @@ "@ngx-translate/http-loader": "^6.0.0", "ace-builds": "^1.4.12", "angular-gridster2": "~11.2.0", - "angular2-hotkeys": "^2.2.0", + "angular2-hotkeys": "^2.4.0", "canvas-gauges": "^2.1.7", "compass-sass-mixins": "^0.12.7", "core-js": "^3.18.3", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 5e88917fd1..cd28f3ef00 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -2581,13 +2581,14 @@ angular-gridster2@~11.2.0: dependencies: tslib "^2.0.0" -angular2-hotkeys@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/angular2-hotkeys/-/angular2-hotkeys-2.2.0.tgz#7b52ba99c42c56656360953ab79d776f583d1ab8" - integrity sha512-2O2wtPyscQU/PtyPc+TefSHAql0VI51rrKyIt87YAvBaGUZEj5PZG2QtC7kYI3sFhXYlvrNefUxXoehFjEVQAQ== +angular2-hotkeys@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/angular2-hotkeys/-/angular2-hotkeys-2.4.0.tgz#b814ccc43bb55eddff103d2ccf42afd832e3ff9d" + integrity sha512-m1UHmPBCKNUoGDPbyfLxUcUXd7vn1welfpfCLv7hEM2HIYfEtFo158xx7l4mAufEeE5179uFJggSQcVwJennfg== dependencies: "@types/mousetrap" "^1.6.0" mousetrap "^1.6.0" + tslib "^2.0.0" ansi-colors@4.1.1: version "4.1.1" From d8879de327e55258792c6a565e5046c33716b621 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:50:11 +0200 Subject: [PATCH 275/303] Angular core and cli 12 --- ui-ngx/package.json | 30 +- ui-ngx/src/environments/environment.ts | 2 +- ui-ngx/src/polyfills.ts | 2 +- ui-ngx/src/test.ts | 2 +- ui-ngx/yarn.lock | 2861 +++++++++++++++++++++--- 5 files changed, 2590 insertions(+), 307 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 08ef9ad473..06ec15ace2 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -5,7 +5,7 @@ "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", "build": "ng build", - "build:prod": "ng build --prod --vendor-chunk", + "build:prod": "ng build --configuration production --vendor-chunk", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", @@ -13,17 +13,17 @@ }, "private": true, "dependencies": { - "@angular/animations": "^11.2.14", + "@angular/animations": "^12.2.13", "@angular/cdk": "^11.2.13", - "@angular/common": "^11.2.14", - "@angular/compiler": "^11.2.14", - "@angular/core": "^11.2.14", + "@angular/common": "^12.2.13", + "@angular/compiler": "^12.2.13", + "@angular/core": "^12.2.13", "@angular/flex-layout": "^11.0.0-beta.33", - "@angular/forms": "^11.2.14", + "@angular/forms": "^12.2.13", "@angular/material": "^11.2.13", - "@angular/platform-browser": "^11.2.14", - "@angular/platform-browser-dynamic": "^11.2.14", - "@angular/router": "^11.2.14", + "@angular/platform-browser": "^12.2.13", + "@angular/platform-browser-dynamic": "^12.2.13", + "@angular/router": "^12.2.13", "@auth0/angular-jwt": "^5.0.2", "@date-io/date-fns": "^2.10.11", "@flowjs/flow.js": "^2.14.1", @@ -101,10 +101,10 @@ }, "devDependencies": { "@angular-builders/custom-webpack": "~11.1.1", - "@angular-devkit/build-angular": "^0.1102.13", - "@angular/cli": "^11.2.13", - "@angular/compiler-cli": "^11.2.14", - "@angular/language-service": "^11.2.14", + "@angular-devkit/build-angular": "^12.2.13", + "@angular/cli": "^12.2.13", + "@angular/compiler-cli": "^12.2.13", + "@angular/language-service": "^12.2.13", "@ngtools/webpack": "~12.2.13", "@types/canvas-gauges": "^2.1.2", "@types/flot": "^0.0.31", @@ -142,10 +142,10 @@ "protractor": "~7.0.0", "ts-node": "^9.0.0", "tslint": "~6.1.3", - "typescript": "~4.0.3", + "typescript": "~4.3.5", "webpack": "^5.64.4" }, "resolutions": { "lodash": "~4.17.21" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/environments/environment.ts b/ui-ngx/src/environments/environment.ts index fd558aa87b..35f971c1d2 100644 --- a/ui-ngx/src/environments/environment.ts +++ b/ui-ngx/src/environments/environment.ts @@ -35,4 +35,4 @@ export const environment = { * This import should be commented out in production mode because it will have a negative impact * on performance if an error is thrown. */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. +// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. diff --git a/ui-ngx/src/polyfills.ts b/ui-ngx/src/polyfills.ts index 9da0bd3053..7c910914db 100644 --- a/ui-ngx/src/polyfills.ts +++ b/ui-ngx/src/polyfills.ts @@ -73,7 +73,7 @@ */ import './zone-flags'; -import 'zone.js/dist/zone'; // Included with Angular CLI. +import 'zone.js'; // Included with Angular CLI. import 'core-js/es/array'; /*************************************************************************************************** diff --git a/ui-ngx/src/test.ts b/ui-ngx/src/test.ts index 2fad0ab73c..567a569ad0 100644 --- a/ui-ngx/src/test.ts +++ b/ui-ngx/src/test.ts @@ -16,7 +16,7 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/zone-testing'; +import 'zone.js/testing'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index cd28f3ef00..b1b280a8bc 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@ampproject/remapping@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-1.0.1.tgz#1398e73e567c2a7992df6554c15bb94a89b68ba2" + integrity sha512-Ta9bMA3EtUHDaZJXqUoT5cn/EecwOp+SXpKJqxDbDuMbLvEMu6YTyDDuvTWeStODfdmXyfMo7LymQyPkN3BicA== + dependencies: + "@jridgewell/resolve-uri" "1.0.0" + sourcemap-codec "1.4.8" + "@angular-builders/custom-webpack@~11.1.1": version "11.1.1" resolved "https://registry.yarnpkg.com/@angular-builders/custom-webpack/-/custom-webpack-11.1.1.tgz#5ef535f5c51cb2f5a27f53fcfab54176cd1d14d4" @@ -23,7 +31,15 @@ "@angular-devkit/core" "11.2.13" rxjs "6.6.3" -"@angular-devkit/build-angular@>=0.1100.0 < 0.1200.0", "@angular-devkit/build-angular@^0.1102.13": +"@angular-devkit/architect@0.1202.13": + version "0.1202.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1202.13.tgz#b9b883d62f628a6b31ce071da91e268f61da00ef" + integrity sha512-LXgiidXwBgyWPqqWK4xR1/kCPQTMTzG5w+s7+LvENUZwbcdl6CKrOMjfgjo6WPr6yeq+WWQvPCD4pZ6nXRTm7A== + dependencies: + "@angular-devkit/core" "12.2.13" + rxjs "6.6.7" + +"@angular-devkit/build-angular@>=0.1100.0 < 0.1200.0": version "0.1102.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.1102.13.tgz#3d7bac8d471c6f2b7067236151cc5018b2ad1a51" integrity sha512-1ezVautOtfl16pOT3p7Z9IPd7vSyy6lZ+HZWqMK1AmUjNhsEA2WeuC/XznGatC3K+9IcfV+eSm6cP0iuLyETzw== @@ -102,6 +118,83 @@ webpack-subresource-integrity "1.5.2" worker-plugin "5.0.0" +"@angular-devkit/build-angular@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-12.2.13.tgz#f5564d3ec9db132956473bb904bb3590482f5b36" + integrity sha512-iJ1P/RZ1hk2n/HtEqB5ohXvHa+Hf0BXShYskSGrn6/klcTb0eJTCREsFxHk7mNEmRIGPWkjbLAslqpPgwiagXg== + dependencies: + "@ampproject/remapping" "1.0.1" + "@angular-devkit/architect" "0.1202.13" + "@angular-devkit/build-optimizer" "0.1202.13" + "@angular-devkit/build-webpack" "0.1202.13" + "@angular-devkit/core" "12.2.13" + "@babel/core" "7.14.8" + "@babel/generator" "7.14.8" + "@babel/helper-annotate-as-pure" "7.14.5" + "@babel/plugin-proposal-async-generator-functions" "7.14.7" + "@babel/plugin-transform-async-to-generator" "7.14.5" + "@babel/plugin-transform-runtime" "7.14.5" + "@babel/preset-env" "7.14.8" + "@babel/runtime" "7.14.8" + "@babel/template" "7.14.5" + "@discoveryjs/json-ext" "0.5.3" + "@jsdevtools/coverage-istanbul-loader" "3.0.5" + "@ngtools/webpack" "12.2.13" + ansi-colors "4.1.1" + babel-loader "8.2.2" + browserslist "^4.9.1" + cacache "15.2.0" + caniuse-lite "^1.0.30001032" + circular-dependency-plugin "5.2.2" + copy-webpack-plugin "9.0.1" + core-js "3.16.0" + critters "0.0.12" + css-loader "6.2.0" + css-minimizer-webpack-plugin "3.0.2" + esbuild-wasm "0.13.8" + find-cache-dir "3.3.1" + glob "7.1.7" + https-proxy-agent "5.0.0" + inquirer "8.1.2" + karma-source-map-support "1.4.0" + less "4.1.1" + less-loader "10.0.1" + license-webpack-plugin "2.3.20" + loader-utils "2.0.0" + mini-css-extract-plugin "2.4.2" + minimatch "3.0.4" + open "8.2.1" + ora "5.4.1" + parse5-html-rewriting-stream "6.0.1" + piscina "3.1.0" + postcss "8.3.6" + postcss-import "14.0.2" + postcss-loader "6.1.1" + postcss-preset-env "6.7.0" + regenerator-runtime "0.13.9" + resolve-url-loader "4.0.0" + rxjs "6.6.7" + sass "1.36.0" + sass-loader "12.1.0" + semver "7.3.5" + source-map-loader "3.0.0" + source-map-support "0.5.19" + style-loader "3.2.1" + stylus "0.54.8" + stylus-loader "6.1.0" + terser "5.7.1" + terser-webpack-plugin "5.1.4" + text-table "0.2.0" + tree-kill "1.2.2" + tslib "2.3.0" + webpack "5.50.0" + webpack-dev-middleware "5.0.0" + webpack-dev-server "3.11.2" + webpack-merge "5.8.0" + webpack-subresource-integrity "1.5.2" + optionalDependencies: + esbuild "0.13.8" + "@angular-devkit/build-optimizer@0.1102.13": version "0.1102.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1102.13.tgz#5c60fa88db41f22f296f1ee628f4c6abe90dac95" @@ -113,6 +206,15 @@ typescript "4.1.5" webpack-sources "2.2.0" +"@angular-devkit/build-optimizer@0.1202.13": + version "0.1202.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1202.13.tgz#7f0b13368cc2a08b1f4789ab1296a1609f5049ea" + integrity sha512-XX6rX5+mAl+MiIJDvi5N5mBLWOoskhMJ5r/G1PEqv0CMMJSSw60zUTndjxfq/nrX0PtsV3j/aqHN4Sj0w/gumg== + dependencies: + source-map "0.7.3" + tslib "2.3.0" + typescript "4.3.5" + "@angular-devkit/build-webpack@0.1102.13": version "0.1102.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1102.13.tgz#d7d552500713278cc3ed28c3cc669f31b4f285a6" @@ -122,6 +224,14 @@ "@angular-devkit/core" "11.2.13" rxjs "6.6.3" +"@angular-devkit/build-webpack@0.1202.13": + version "0.1202.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1202.13.tgz#875f9f9677bb10056b52230965dc2f00bd3089dd" + integrity sha512-KafzGyHuU2gBKaSICfMTFP2niTYZ/46DKU94TQ0lCILdJZsj0NE5M/288LSCbYgu2c7srJKz+Rvb+JcYGxIZ1g== + dependencies: + "@angular-devkit/architect" "0.1202.13" + rxjs "6.6.7" + "@angular-devkit/core@11.2.13", "@angular-devkit/core@^11.0.0": version "11.2.13" resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-11.2.13.tgz#7829862132555a52009d0af9671b06ffdf9200f1" @@ -133,21 +243,33 @@ rxjs "6.6.3" source-map "0.7.3" -"@angular-devkit/schematics@11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-11.2.13.tgz#ce3b55e7f38ca9c40cb9c9c8d0096bd8e1490bb1" - integrity sha512-HMQWs9tsvmsS/QoL+ayxCYqjpP2Qc1x30EJrDU8zPDsaRCe06Uj7VYedBKlHpDGxh0D2F2oRSG1YkXGHr3H/TQ== +"@angular-devkit/core@12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-12.2.13.tgz#db3929d1bfce71010b37fb7c4e6c33ef80a4f35f" + integrity sha512-9csMF0p+lTvlWnutxxTZ/+pDRMIbXk/TV4MGLbcqUPPfeG3dCRwErns73xLuMTwp9qO/KCLkFqNaM6cGOoqsDA== dependencies: - "@angular-devkit/core" "11.2.13" - ora "5.3.0" - rxjs "6.6.3" + ajv "8.6.2" + ajv-formats "2.1.0" + fast-json-stable-stringify "2.1.0" + magic-string "0.25.7" + rxjs "6.6.7" + source-map "0.7.3" -"@angular/animations@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-11.2.14.tgz#cf119ea779bf11bd3759f1355c85e4e8e9e7bb03" - integrity sha512-Heq/nNrCmb3jbkusu+BQszOecfFI/31Oxxj+CDQkqqYpBcswk6bOJLoEE472o+vmgxaXbgeflU9qbIiCQhpMFA== +"@angular-devkit/schematics@12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-12.2.13.tgz#6464d86fa3ccd0efb5ead46c793cef9ec45c7758" + integrity sha512-LQTv72R5Ma1uowMEeii2wIoDWI4bYQyZvunqPy9jRveBTjli2yVwwcOziGCVyttwlYs46bSdxThgeEvVIako2w== dependencies: - tslib "^2.0.0" + "@angular-devkit/core" "12.2.13" + ora "5.4.1" + rxjs "6.6.7" + +"@angular/animations@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-12.2.13.tgz#909b79c56a85bb31c0605ed419850340b5580be9" + integrity sha512-qpdmvu+nxsKnimJ3Hc1joNuzK7xXYyE+VtNMk4K77Ao/9+5C/juGMce85DhqZCcu1xraZ3YYIrzYmL/GgdUK4g== + dependencies: + tslib "^2.2.0" "@angular/cdk@^11.2.13": version "11.2.13" @@ -158,85 +280,81 @@ optionalDependencies: parse5 "^5.0.0" -"@angular/cli@^11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-11.2.13.tgz#10534aa2d16e438cf4bb0e912ab28a1eb67dafe1" - integrity sha512-ma5+Iu24XacSY5WrcZ5WJQMv7/RPhWxtbkpr11hndlgUmjmM6dYNGHJOFRXcU7bP7kbOVdd7cZ++2vMGlh0kcg== +"@angular/cli@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-12.2.13.tgz#ca586c14a6f83bb4390875be0a0fa709b9a2ae29" + integrity sha512-Yz6MuwdxxP6U2i8iRuCSNZeJxlLDPshT/joymCsFdjwSMGEH9Kk9DdvAfFYfzdHGdHbGrDdASJ4G+uALyNSLxw== dependencies: - "@angular-devkit/architect" "0.1102.13" - "@angular-devkit/core" "11.2.13" - "@angular-devkit/schematics" "11.2.13" - "@schematics/angular" "11.2.13" - "@schematics/update" "0.1102.13" + "@angular-devkit/architect" "0.1202.13" + "@angular-devkit/core" "12.2.13" + "@angular-devkit/schematics" "12.2.13" + "@schematics/angular" "12.2.13" "@yarnpkg/lockfile" "1.1.0" ansi-colors "4.1.1" - debug "4.3.1" + debug "4.3.2" ini "2.0.0" - inquirer "7.3.3" + inquirer "8.1.2" jsonc-parser "3.0.0" - npm-package-arg "8.1.0" - npm-pick-manifest "6.1.0" - open "7.4.0" - ora "5.3.0" - pacote "11.2.4" - resolve "1.19.0" - rimraf "3.0.2" - semver "7.3.4" - symbol-observable "3.0.0" - universal-analytics "0.4.23" + npm-package-arg "8.1.5" + npm-pick-manifest "6.1.1" + open "8.2.1" + ora "5.4.1" + pacote "11.3.5" + resolve "1.20.0" + semver "7.3.5" + symbol-observable "4.0.0" uuid "8.3.2" -"@angular/common@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-11.2.14.tgz#52887277b0ae0438e584f9ae97b417ee51a694b5" - integrity sha512-ZSLV/3j7eCTyLf/8g4yBFLWySjiLz3vLJAGWscYoUpnJWMnug1VRu6zoF/COxCbtORgE+Wz6K0uhfS6MziBGVw== +"@angular/common@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-12.2.13.tgz#fe52ffae8668c1dec41b26cdc3a749101399e1fe" + integrity sha512-I1t/jl9ojCwTJKT7PKHnk23D+vMHTHS/9qZ2nndCjzGusMK8029nn8l3tHAkwefvxZWSaLAk1MgsVcP+rHQNsQ== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" -"@angular/compiler-cli@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-11.2.14.tgz#fdd22aeec25aa2477595bed631d19e977254ecc5" - integrity sha512-A7ltnCp03/EVqK/Q3tVUDsokgz5GHW3dSPGl0Csk7Ys5uBB9ibHTmVt4eiXA4jt0+6Bk+mKxwe5BEDqLvwYFAg== +"@angular/compiler-cli@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-12.2.13.tgz#3ce463263e80a861e14af2ed3ba81598060e3ce0" + integrity sha512-qmnmihl3SCRooj/mCsNIZLtnQ6qbx1/L6aMIEQosPvQhMeGMt8GCYvQPE8IZ+sahv7fih95HCWNa9TeLpOylug== dependencies: "@babel/core" "^7.8.6" "@babel/types" "^7.8.6" canonical-path "1.0.0" chokidar "^3.0.0" convert-source-map "^1.5.1" - dependency-graph "^0.7.2" - fs-extra "4.0.2" + dependency-graph "^0.11.0" magic-string "^0.25.0" minimist "^1.2.0" reflect-metadata "^0.1.2" - semver "^6.3.0" + semver "^7.0.0" source-map "^0.6.1" sourcemap-codec "^1.4.8" - tslib "^2.0.0" - yargs "^16.2.0" + tslib "^2.2.0" + yargs "^17.0.0" "@angular/compiler@9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.0.0.tgz#87e0bef4c369b6cadae07e3a4295778fc93799d5" integrity sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ== -"@angular/compiler@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-11.2.14.tgz#9d3ea26b4d2d858aab935f69af9e201f53453a0f" - integrity sha512-XBOK3HgA+/y6Cz7kOX4zcJYmgJ264XnfcbXUMU2cD7Ac+mbNhLPKohWrEiSWalfcjnpf5gRfufQrQP7lpAGu0A== +"@angular/compiler@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-12.2.13.tgz#7eef6fdb81b9de6fd0e2cdda2ad8a084c1d9535b" + integrity sha512-L0saTTJJtxldjhaGIL6b1BCfodPOEz4Wrev3pEUK5UcODooj5HLiE/aO6jiNb8M4XTbdqByKyqvZyWzGHeexVQ== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" "@angular/core@9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.0.0.tgz#227dc53e1ac81824f998c6e76000b7efc522641e" integrity sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w== -"@angular/core@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-11.2.14.tgz#3ebe298c79d5413dc670d56b7f503bd4d788d4a8" - integrity sha512-vpR4XqBGitk1Faph37CSpemwIYTmJ3pdIVNoHKP6jLonpWu+0azkchf0f7oD8/2ivj2F81opcIw0tcsy/D/5Vg== +"@angular/core@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-12.2.13.tgz#fc40acbdcee5c5878bd249ddc0d643be724076c3" + integrity sha512-tZ5nAnmOi418JDaJIFiiP9z2JrluMJZvUvXO4QDUs52BXaL2yuP7MJ2LczWOVJXrBLZXeZGfjDjZmaFPA24grg== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" "@angular/flex-layout@^11.0.0-beta.33": version "11.0.0-beta.33" @@ -245,17 +363,17 @@ dependencies: tslib "^2.0.0" -"@angular/forms@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-11.2.14.tgz#dc858408f7647f4fd033996a03aa74df18a02079" - integrity sha512-4LWqY6KEIk1AZQFnk+4PJSOCamlD4tumuVN06gO4D0dZo9Cx+GcvW6pM6N0CPubRvPs3sScCnu20WT11HNWC1w== +"@angular/forms@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-12.2.13.tgz#4de90e88991c274b5d5e3ab0300267e161ba78f2" + integrity sha512-wa7I5R8sck2q+VWNL262GJTVxtpEHMys8Bt6oE+lyHB5zlZAgOXwAb8GE4XVwuc+BZU1Gvrocn21P/8KvDY1uw== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" -"@angular/language-service@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-11.2.14.tgz#452369cdffe76ac6d07836596fb47f9e69a6d119" - integrity sha512-3+0F0X4r1WeNOV6VmaMzYnJENPVmLX2/MX3/lugwZPNYKVXl/oGyh/4PB8ktntIj0tnxQuErzqRSeucNStNGRw== +"@angular/language-service@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.2.13.tgz#326045a328f8a962287037d7a85be8120074421c" + integrity sha512-jb9s3IJuWNKTRcM90NOwvMfiy85nnKfTxxLVn8/QFMO6+Ps/hsVZNp+W/TmAEDvCkon+9q0O4hwa4MY1m/Dlkw== "@angular/material@^11.2.13": version "11.2.13" @@ -264,32 +382,37 @@ dependencies: tslib "^2.0.0" -"@angular/platform-browser-dynamic@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.14.tgz#3c7fff1a1daacba5390acf033d28c377ec281166" - integrity sha512-TWTPdFs6iBBcp+/YMsgCRQwdHpWGq8KjeJDJ2tfatGgBD3Gqt2YaHOMST1zPW6RkrmupytTejuVqXzeaKWFxuw== +"@angular/platform-browser-dynamic@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-12.2.13.tgz#9ee6309f511da419d5d80a1a8279adc806e92f04" + integrity sha512-a7y7R3vOXhMAk9uQWK5/23DefahuF0UYJSFM/wKeVo5zR+qOCVCTfafkJMcWbuZWTrSDbVafJ1xbcWnu3+TkCg== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" -"@angular/platform-browser@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-11.2.14.tgz#e52ad7a54a42a865033a17e57e213013919f1b1d" - integrity sha512-fb7b7ss/gRoP8wLAN17W62leMgjynuyjEPU2eUoAAazsG9f2cgM+z3rK29GYncDVyYQxZUZYnjSqvL6GSXx86A== +"@angular/platform-browser@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-12.2.13.tgz#769fb148b2128663d6b405d2a41023f2cdaa1c95" + integrity sha512-Ua8m2GtG2msqz/Mr/MK7s8RXud554x8cup2THVAwetyTaY5th/1LOZX0hhDIhfsxBCLHnC53LRhMbSsI0cikOg== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" -"@angular/router@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-11.2.14.tgz#4a8eb6d010a1a45c8e7f0c3b5b705959bdb69294" - integrity sha512-3aYBmj+zrEL9yf/ntIQxHIYaWShZOBKP3U07X2mX+TPMpGlvHDnR7L6bWhQVZwewzMMz7YVR16ldg50IFuAlfA== +"@angular/router@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-12.2.13.tgz#e5b939a9675f9d4834fee3e75eb8d040ef63b3b5" + integrity sha512-HZL/Pzp6I7fQiMLrzfEzhnqhgNcGcFjBgMMOoLp5IA1IV26rp1NU6zYJzPrXtopBx7XLl8BECehAwFqrJsu/PQ== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" "@ant-design/css-animation@^1.7.2": version "1.7.3" resolved "https://registry.yarnpkg.com/@ant-design/css-animation/-/css-animation-1.7.3.tgz#60a1c970014e86b28f940510d69e503e428f1136" integrity sha512-LrX0OGZtW+W6iLnTAqnTaoIsRelYeuLZWsrmBJFUXDALQphPsN8cE5DCsmoSlL0QYb94BQxINiuS70Ar/8BNgA== +"@assemblyscript/loader@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06" + integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg== + "@auth0/angular-jwt@^5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@auth0/angular-jwt/-/angular-jwt-5.0.2.tgz#0a23f240e8c6ed37c5c7a354ad79a755a217936e" @@ -311,11 +434,23 @@ dependencies: "@babel/highlight" "^7.12.13" +"@babel/code-frame@^7.14.5", "@babel/code-frame@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" + integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== + dependencies: + "@babel/highlight" "^7.16.0" + "@babel/compat-data@^7.12.7", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.16.0": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== + "@babel/core@7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" @@ -337,6 +472,27 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.8.tgz#20cdf7c84b5d86d83fac8710a8bc605a7ba3f010" + integrity sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.14.8" + "@babel/helper-compilation-targets" "^7.14.5" + "@babel/helper-module-transforms" "^7.14.8" + "@babel/helpers" "^7.14.8" + "@babel/parser" "^7.14.8" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.14.8" + "@babel/types" "^7.14.8" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + "@babel/core@^7.7.5": version "7.11.6" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" @@ -389,6 +545,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.8.tgz#bf86fd6af96cf3b74395a8ca409515f89423e070" + integrity sha512-cYDUpvIzhBVnMzRoY1fkSEhK/HmwEVwlyULYgn/tMQYd6Obag3ylCjONle3gdErfXBW61SVTlR9QR7uWlgeIkg== + dependencies: + "@babel/types" "^7.14.8" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/generator@^7.11.5", "@babel/generator@^7.11.6": version "7.11.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" @@ -407,6 +572,22 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.14.8", "@babel/generator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" + integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== + dependencies: + "@babel/types" "^7.16.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61" + integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA== + dependencies: + "@babel/types" "^7.14.5" + "@babel/helper-annotate-as-pure@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" @@ -421,6 +602,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" + integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc" @@ -429,6 +617,14 @@ "@babel/helper-explode-assignable-expression" "^7.12.13" "@babel/types" "^7.12.13" +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz#f1a686b92da794020c26582eb852e9accd0d7882" + integrity sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-compilation-targets@^7.12.5", "@babel/helper-compilation-targets@^7.13.16": version "7.13.16" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" @@ -439,6 +635,16 @@ browserslist "^4.14.5" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" + integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.17.5" + semver "^6.3.0" + "@babel/helper-create-class-features-plugin@^7.13.0": version "7.14.3" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.3.tgz#832111bcf4f57ca57a4c5b1a000fc125abc6554a" @@ -451,6 +657,18 @@ "@babel/helper-replace-supers" "^7.14.3" "@babel/helper-split-export-declaration" "^7.12.13" +"@babel/helper-create-class-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" + integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-create-regexp-features-plugin@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" @@ -468,6 +686,28 @@ "@babel/helper-annotate-as-pure" "^7.12.13" regexpu-core "^4.7.1" +"@babel/helper-create-regexp-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" + integrity sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.2.2", "@babel/helper-define-polyfill-provider@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.4.tgz#8867aed79d3ea6cade40f801efb7ac5c66916b10" + integrity sha512-OrpPZ97s+aPi6h2n1OXzdhVis1SGSsMU2aMHgLcOKfsp4/v1NWpx3CWT3lBj5eeBq9cDkPkh+YCfdF7O12uNDQ== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + "@babel/helper-explode-assignable-expression@^7.12.13": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f" @@ -475,6 +715,13 @@ dependencies: "@babel/types" "^7.13.0" +"@babel/helper-explode-assignable-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" + integrity sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-function-name@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" @@ -493,6 +740,15 @@ "@babel/template" "^7.12.13" "@babel/types" "^7.14.2" +"@babel/helper-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" + integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== + dependencies: + "@babel/helper-get-function-arity" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-get-function-arity@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" @@ -507,6 +763,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-get-function-arity@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" + integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-hoist-variables@^7.13.0": version "7.13.16" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.16.tgz#1b1651249e94b51f8f0d33439843e33e39775b30" @@ -515,6 +778,13 @@ "@babel/traverse" "^7.13.15" "@babel/types" "^7.13.16" +"@babel/helper-hoist-variables@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" + integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-member-expression-to-functions@^7.10.4": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" @@ -529,6 +799,13 @@ dependencies: "@babel/types" "^7.13.12" +"@babel/helper-member-expression-to-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" + integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-module-imports@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" @@ -543,6 +820,13 @@ dependencies: "@babel/types" "^7.13.12" +"@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" + integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-module-transforms@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" @@ -570,6 +854,20 @@ "@babel/traverse" "^7.14.2" "@babel/types" "^7.14.2" +"@babel/helper-module-transforms@^7.14.8", "@babel/helper-module-transforms@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" + integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-simple-access" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-optimise-call-expression@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" @@ -584,6 +882,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-optimise-call-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" + integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" @@ -594,6 +899,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== +"@babel/helper-plugin-utils@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + "@babel/helper-regex@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" @@ -610,6 +920,15 @@ "@babel/helper-wrap-function" "^7.13.0" "@babel/types" "^7.13.0" +"@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.16.0", "@babel/helper-remap-async-to-generator@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz#5d7902f61349ff6b963e07f06a389ce139fbfe6e" + integrity sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-wrap-function" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-replace-supers@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" @@ -630,6 +949,16 @@ "@babel/traverse" "^7.14.2" "@babel/types" "^7.14.2" +"@babel/helper-replace-supers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" + integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-simple-access@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" @@ -645,6 +974,13 @@ dependencies: "@babel/types" "^7.13.12" +"@babel/helper-simple-access@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" + integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-skip-transparent-expression-wrappers@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" @@ -652,6 +988,13 @@ dependencies: "@babel/types" "^7.12.1" +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-split-export-declaration@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" @@ -666,6 +1009,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-split-export-declaration@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" + integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-validator-identifier@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" @@ -676,11 +1026,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== +"@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== + "@babel/helper-validator-option@^7.12.11", "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== + "@babel/helper-wrap-function@^7.13.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4" @@ -691,6 +1051,16 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.0" +"@babel/helper-wrap-function@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" + integrity sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g== + dependencies: + "@babel/helper-function-name" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helpers@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" @@ -709,6 +1079,15 @@ "@babel/traverse" "^7.14.0" "@babel/types" "^7.14.0" +"@babel/helpers@^7.14.8": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" + integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== + dependencies: + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.3" + "@babel/types" "^7.16.0" + "@babel/highlight@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" @@ -727,6 +1106,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.10.4", "@babel/parser@^7.11.5": version "7.11.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" @@ -737,6 +1125,29 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.3.tgz#9b530eecb071fd0c93519df25c5ff9f14759f298" integrity sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ== +"@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz#358972eaab006f5eb0826183b0c93cbcaf13e1e2" + integrity sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + +"@babel/plugin-proposal-async-generator-functions@7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz#784a48c3d8ed073f65adcf30b57bcbf6c8119ace" + integrity sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.14.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-proposal-async-generator-functions@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.2.tgz#3a2085abbf5d5f962d480dbc81347385ed62eb1e" @@ -746,6 +1157,15 @@ "@babel/helper-remap-async-to-generator" "^7.13.0" "@babel/plugin-syntax-async-generators" "^7.8.4" +"@babel/plugin-proposal-async-generator-functions@^7.14.7": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz#e606eb6015fec6fa5978c940f315eae4e300b081" + integrity sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.4" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-proposal-class-properties@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" @@ -754,6 +1174,23 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-class-properties@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" + integrity sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-class-static-block@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz#5296942c564d8144c83eea347d0aa8a0b89170e7" + integrity sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-proposal-dynamic-import@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.2.tgz#01ebabd7c381cff231fa43e302939a9de5be9d9f" @@ -762,6 +1199,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-dynamic-import" "^7.8.3" +"@babel/plugin-proposal-dynamic-import@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" + integrity sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-export-namespace-from@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.2.tgz#62542f94aa9ce8f6dba79eec698af22112253791" @@ -770,6 +1215,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" +"@babel/plugin-proposal-export-namespace-from@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" + integrity sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-proposal-json-strings@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.2.tgz#830b4e2426a782e8b2878fbfe2cba85b70cbf98c" @@ -778,6 +1231,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-json-strings" "^7.8.3" +"@babel/plugin-proposal-json-strings@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" + integrity sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-proposal-logical-assignment-operators@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.2.tgz#222348c080a1678e0e74ea63fe76f275882d1fd7" @@ -786,6 +1247,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" +"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" + integrity sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.2.tgz#425b11dc62fc26939a2ab42cbba680bdf5734546" @@ -794,6 +1263,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" +"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" + integrity sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-numeric-separator@^7.12.7": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.2.tgz#82b4cc06571143faf50626104b335dd71baa4f9e" @@ -802,6 +1279,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-numeric-separator" "^7.10.4" +"@babel/plugin-proposal-numeric-separator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" + integrity sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.2.tgz#e17d418f81cc103fedd4ce037e181c8056225abc" @@ -813,6 +1298,17 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-transform-parameters" "^7.14.2" +"@babel/plugin-proposal-object-rest-spread@^7.14.7": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" + integrity sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.0" + "@babel/plugin-proposal-optional-catch-binding@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.2.tgz#150d4e58e525b16a9a1431bd5326c4eed870d717" @@ -821,6 +1317,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" +"@babel/plugin-proposal-optional-catch-binding@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" + integrity sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining@^7.12.7": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.2.tgz#df8171a8b9c43ebf4c1dabe6311b432d83e1b34e" @@ -830,6 +1334,15 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" "@babel/plugin-syntax-optional-chaining" "^7.8.3" +"@babel/plugin-proposal-optional-chaining@^7.14.5", "@babel/plugin-proposal-optional-chaining@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" + integrity sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-proposal-private-methods@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz#04bd4c6d40f6e6bbfa2f57e2d8094bad900ef787" @@ -838,6 +1351,24 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-private-methods@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" + integrity sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-private-property-in-object@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz#69e935b2c5c79d2488112d886f0c4e2790fee76f" + integrity sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-proposal-unicode-property-regex@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" @@ -846,6 +1377,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-proposal-unicode-property-regex@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" + integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" @@ -861,13 +1400,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.1": +"@babel/plugin-syntax-class-properties@^7.12.1", "@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" @@ -931,6 +1477,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-top-level-await@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" @@ -938,6 +1491,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-arrow-functions@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" @@ -945,6 +1505,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-arrow-functions@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" + integrity sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-async-to-generator@7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz#3849a49cc2a22e9743cbd6b52926d30337229af1" @@ -954,6 +1521,15 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-remap-async-to-generator" "^7.12.1" +"@babel/plugin-transform-async-to-generator@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" + integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.14.5" + "@babel/plugin-transform-async-to-generator@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f" @@ -963,6 +1539,15 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-remap-async-to-generator" "^7.13.0" +"@babel/plugin-transform-async-to-generator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" + integrity sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.0" + "@babel/plugin-transform-block-scoped-functions@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4" @@ -970,6 +1555,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-block-scoped-functions@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" + integrity sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-block-scoping@^7.12.11": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.2.tgz#761cb12ab5a88d640ad4af4aa81f820e6b5fdf5c" @@ -977,6 +1569,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-block-scoping@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" + integrity sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-classes@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.2.tgz#3f1196c5709f064c252ad056207d87b7aeb2d03d" @@ -990,6 +1589,19 @@ "@babel/helper-split-export-declaration" "^7.12.13" globals "^11.1.0" +"@babel/plugin-transform-classes@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" + integrity sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + globals "^11.1.0" + "@babel/plugin-transform-computed-properties@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed" @@ -997,6 +1609,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-computed-properties@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" + integrity sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-destructuring@^7.12.1": version "7.13.17" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz#678d96576638c19d5b36b332504d3fd6e06dea27" @@ -1004,6 +1623,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-destructuring@^7.14.7": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" + integrity sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-dotall-regex@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad" @@ -1012,6 +1638,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-dotall-regex@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" + integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" @@ -1027,6 +1661,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-duplicate-keys@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" + integrity sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-exponentiation-operator@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1" @@ -1035,6 +1676,14 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-exponentiation-operator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" + integrity sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-for-of@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062" @@ -1042,6 +1691,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-for-of@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" + integrity sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-function-name@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051" @@ -1050,6 +1706,14 @@ "@babel/helper-function-name" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-function-name@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" + integrity sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg== + dependencies: + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-literals@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9" @@ -1057,6 +1721,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-literals@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" + integrity sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-member-expression-literals@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40" @@ -1064,6 +1735,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-member-expression-literals@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" + integrity sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-modules-amd@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.2.tgz#6622806fe1a7c07a1388444222ef9535f2ca17b0" @@ -1073,6 +1751,15 @@ "@babel/helper-plugin-utils" "^7.13.0" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-amd@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" + integrity sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-dynamic-import-node "^2.3.3" + "@babel/plugin-transform-modules-commonjs@^7.12.1": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" @@ -1083,6 +1770,16 @@ "@babel/helper-simple-access" "^7.13.12" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-commonjs@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" + integrity sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.16.0" + babel-plugin-dynamic-import-node "^2.3.3" + "@babel/plugin-transform-modules-systemjs@^7.12.1": version "7.13.8" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz#6d066ee2bff3c7b3d60bf28dec169ad993831ae3" @@ -1094,6 +1791,17 @@ "@babel/helper-validator-identifier" "^7.12.11" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-systemjs@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" + integrity sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg== + dependencies: + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-identifier" "^7.15.7" + babel-plugin-dynamic-import-node "^2.3.3" + "@babel/plugin-transform-modules-umd@^7.12.1": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.0.tgz#2f8179d1bbc9263665ce4a65f305526b2ea8ac34" @@ -1102,6 +1810,14 @@ "@babel/helper-module-transforms" "^7.14.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-modules-umd@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" + integrity sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-named-capturing-groups-regex@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz#2213725a5f5bbbe364b50c3ba5998c9599c5c9d9" @@ -1109,6 +1825,13 @@ dependencies: "@babel/helper-create-regexp-features-plugin" "^7.12.13" +"@babel/plugin-transform-named-capturing-groups-regex@^7.14.7": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" + integrity sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/plugin-transform-new-target@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz#e22d8c3af24b150dd528cbd6e685e799bf1c351c" @@ -1116,6 +1839,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-new-target@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" + integrity sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-object-super@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7" @@ -1124,6 +1854,14 @@ "@babel/helper-plugin-utils" "^7.12.13" "@babel/helper-replace-supers" "^7.12.13" +"@babel/plugin-transform-object-super@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" + integrity sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.14.2": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.2.tgz#e4290f72e0e9e831000d066427c4667098decc31" @@ -1131,6 +1869,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-parameters@^7.14.5", "@babel/plugin-transform-parameters@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz#fa9e4c874ee5223f891ee6fa8d737f4766d31d15" + integrity sha512-3MaDpJrOXT1MZ/WCmkOFo7EtmVVC8H4EUZVrHvFOsmwkk4lOjQj8rzv8JKUZV4YoQKeoIgk07GO+acPU9IMu/w== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-property-literals@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81" @@ -1138,6 +1883,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-property-literals@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" + integrity sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-regenerator@^7.12.1": version "7.13.15" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39" @@ -1145,6 +1897,13 @@ dependencies: regenerator-transform "^0.14.2" +"@babel/plugin-transform-regenerator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" + integrity sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg== + dependencies: + regenerator-transform "^0.14.2" + "@babel/plugin-transform-reserved-words@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz#7d9988d4f06e0fe697ea1d9803188aa18b472695" @@ -1152,6 +1911,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-reserved-words@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" + integrity sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-runtime@7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.10.tgz#af0fded4e846c4b37078e8e5d06deac6cd848562" @@ -1161,6 +1927,18 @@ "@babel/helper-plugin-utils" "^7.10.4" semver "^5.5.1" +"@babel/plugin-transform-runtime@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523" + integrity sha512-fPMBhh1AV8ZyneiCIA+wYYUH1arzlXR1UMcApjvchDhfKxhy2r2lReJv8uHEyihi4IFIGlr1Pdx7S5fkESDQsg== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-polyfill-corejs2 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-regenerator "^0.2.2" + semver "^6.3.0" + "@babel/plugin-transform-shorthand-properties@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad" @@ -1168,6 +1946,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-shorthand-properties@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" + integrity sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-spread@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd" @@ -1176,6 +1961,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" +"@babel/plugin-transform-spread@^7.14.6": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" + integrity sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-transform-sticky-regex@^7.12.7": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f" @@ -1183,6 +1976,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-sticky-regex@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" + integrity sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-template-literals@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d" @@ -1190,6 +1990,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-template-literals@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" + integrity sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-typeof-symbol@^7.12.10": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f" @@ -1197,6 +2004,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-typeof-symbol@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" + integrity sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-unicode-escapes@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74" @@ -1204,6 +2018,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-unicode-escapes@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" + integrity sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-unicode-regex@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac" @@ -1212,6 +2033,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-unicode-regex@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" + integrity sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/preset-env@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9" @@ -1284,6 +2113,85 @@ core-js-compat "^3.8.0" semver "^5.5.0" +"@babel/preset-env@7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.8.tgz#254942f5ca80ccabcfbb2a9f524c74bca574005b" + integrity sha512-a9aOppDU93oArQ51H+B8M1vH+tayZbuBqzjOhntGetZVa+4tTu5jp+XTwqHGG2lxslqomPYVSjIxQkFwXzgnxg== + dependencies: + "@babel/compat-data" "^7.14.7" + "@babel/helper-compilation-targets" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5" + "@babel/plugin-proposal-async-generator-functions" "^7.14.7" + "@babel/plugin-proposal-class-properties" "^7.14.5" + "@babel/plugin-proposal-class-static-block" "^7.14.5" + "@babel/plugin-proposal-dynamic-import" "^7.14.5" + "@babel/plugin-proposal-export-namespace-from" "^7.14.5" + "@babel/plugin-proposal-json-strings" "^7.14.5" + "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" + "@babel/plugin-proposal-numeric-separator" "^7.14.5" + "@babel/plugin-proposal-object-rest-spread" "^7.14.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" + "@babel/plugin-proposal-optional-chaining" "^7.14.5" + "@babel/plugin-proposal-private-methods" "^7.14.5" + "@babel/plugin-proposal-private-property-in-object" "^7.14.5" + "@babel/plugin-proposal-unicode-property-regex" "^7.14.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.14.5" + "@babel/plugin-transform-async-to-generator" "^7.14.5" + "@babel/plugin-transform-block-scoped-functions" "^7.14.5" + "@babel/plugin-transform-block-scoping" "^7.14.5" + "@babel/plugin-transform-classes" "^7.14.5" + "@babel/plugin-transform-computed-properties" "^7.14.5" + "@babel/plugin-transform-destructuring" "^7.14.7" + "@babel/plugin-transform-dotall-regex" "^7.14.5" + "@babel/plugin-transform-duplicate-keys" "^7.14.5" + "@babel/plugin-transform-exponentiation-operator" "^7.14.5" + "@babel/plugin-transform-for-of" "^7.14.5" + "@babel/plugin-transform-function-name" "^7.14.5" + "@babel/plugin-transform-literals" "^7.14.5" + "@babel/plugin-transform-member-expression-literals" "^7.14.5" + "@babel/plugin-transform-modules-amd" "^7.14.5" + "@babel/plugin-transform-modules-commonjs" "^7.14.5" + "@babel/plugin-transform-modules-systemjs" "^7.14.5" + "@babel/plugin-transform-modules-umd" "^7.14.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.7" + "@babel/plugin-transform-new-target" "^7.14.5" + "@babel/plugin-transform-object-super" "^7.14.5" + "@babel/plugin-transform-parameters" "^7.14.5" + "@babel/plugin-transform-property-literals" "^7.14.5" + "@babel/plugin-transform-regenerator" "^7.14.5" + "@babel/plugin-transform-reserved-words" "^7.14.5" + "@babel/plugin-transform-shorthand-properties" "^7.14.5" + "@babel/plugin-transform-spread" "^7.14.6" + "@babel/plugin-transform-sticky-regex" "^7.14.5" + "@babel/plugin-transform-template-literals" "^7.14.5" + "@babel/plugin-transform-typeof-symbol" "^7.14.5" + "@babel/plugin-transform-unicode-escapes" "^7.14.5" + "@babel/plugin-transform-unicode-regex" "^7.14.5" + "@babel/preset-modules" "^0.1.4" + "@babel/types" "^7.14.8" + babel-plugin-polyfill-corejs2 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-regenerator "^0.2.2" + core-js-compat "^3.15.0" + semver "^6.3.0" + "@babel/preset-modules@^0.1.3": version "0.1.4" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" @@ -1295,6 +2203,17 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" +"@babel/preset-modules@^0.1.4": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + "@babel/runtime@7.12.5", "@babel/runtime@^7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" @@ -1302,6 +2221,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446" + integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" @@ -1318,6 +2244,15 @@ "@babel/parser" "^7.12.7" "@babel/types" "^7.12.7" +"@babel/template@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" + integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.14.5" + "@babel/types" "^7.14.5" + "@babel/template@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -1336,6 +2271,15 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" +"@babel/template@^7.14.5", "@babel/template@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" + integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5": version "7.11.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" @@ -1365,6 +2309,21 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.14.8", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" + integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/parser" "^7.16.3" + "@babel/types" "^7.16.0" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.4.4": version "7.11.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" @@ -1382,6 +2341,19 @@ "@babel/helper-validator-identifier" "^7.14.0" to-fast-properties "^2.0.0" +"@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + to-fast-properties "^2.0.0" + +"@csstools/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== + "@date-io/core@1.x": version "1.3.13" resolved "https://registry.yarnpkg.com/@date-io/core/-/core-1.3.13.tgz#90c71da493f20204b7a972929cc5c482d078b3fa" @@ -1404,6 +2376,11 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752" integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg== +"@discoveryjs/json-ext@0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d" + integrity sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g== + "@emotion/hash@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" @@ -1422,6 +2399,11 @@ "@types/flowjs" "2.13.3" tslib "^1.9.0" +"@gar/promisify@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" + integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== + "@geoman-io/leaflet-geoman-free@^2.11.3": version "2.11.3" resolved "https://registry.yarnpkg.com/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.11.3.tgz#480164ab76c2b2a885003e0c111284f3c3160a36" @@ -1439,6 +2421,11 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== +"@jridgewell/resolve-uri@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-1.0.0.tgz#3fdf5798f0b49e90155896f6291df186eac06c83" + integrity sha512-9oLAnygRMi8Q5QkYEU4XWK04B+nuoXoxjRvRxgjuChkLZFBja0YPSgdZ7dZtwhncLBcQe/I/E+fLuk5qxcYVJA== + "@jsdevtools/coverage-istanbul-loader@3.0.5": version "3.0.5" resolved "https://registry.yarnpkg.com/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.5.tgz#2a4bc65d0271df8d4435982db4af35d81754ee26" @@ -1575,7 +2562,7 @@ enhanced-resolve "5.7.0" webpack-sources "2.2.0" -"@ngtools/webpack@~12.2.13": +"@ngtools/webpack@12.2.13", "@ngtools/webpack@~12.2.13": version "12.2.13" resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.2.13.tgz#44d711edfa39d175a2d655aa5c6f9968dfedcc35" integrity sha512-krAwMyRqOaC1S0+IxAFid9F6A6ABip2DJ0tgCx26X+1Vw/d1GKtV9ZqDJFizMf5k1ywl9aBlhOazWpq5d6i+gw== @@ -1615,15 +2602,18 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" -"@npmcli/ci-detect@^1.0.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" - integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== +"@npmcli/fs@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f" + integrity sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" -"@npmcli/git@^2.0.1": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.0.9.tgz#915bbfe66300e67b4da5ef765a4475ffb2ca5b6b" - integrity sha512-hTMbMryvOqGLwnmMBKs5usbPsJtyEsMsgXwJbmNrsEuQQh1LAIMDU77IoOrwkCg+NgQWl+ySlarJASwM3SutCA== +"@npmcli/git@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" + integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== dependencies: "@npmcli/promise-spawn" "^1.3.2" lru-cache "^6.0.0" @@ -1634,7 +2624,7 @@ semver "^7.3.5" which "^2.0.2" -"@npmcli/installed-package-contents@^1.0.5": +"@npmcli/installed-package-contents@^1.0.6": version "1.0.7" resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== @@ -1661,40 +2651,25 @@ dependencies: infer-owner "^1.0.4" -"@npmcli/run-script@^1.3.0": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.5.tgz#f250a0c5e1a08a792d775a315d0ff42fc3a51e1d" - integrity sha512-NQspusBCpTjNwNRFMtz2C5MxoxyzlbuJ4YEhxAKrIonTiirKDtatsZictx9RgamQIx6+QuHMNmPl0wQdoESs9A== +"@npmcli/run-script@^1.8.2": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" + integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== dependencies: "@npmcli/node-gyp" "^1.0.2" "@npmcli/promise-spawn" "^1.3.2" - infer-owner "^1.0.4" node-gyp "^7.1.0" read-package-json-fast "^2.0.1" -"@schematics/angular@11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-11.2.13.tgz#a37e9e7a2cf0a37a8948f0afb0f29e6671ce740a" - integrity sha512-cMXWruwSkH2XEKDA8df70Ey/5okdJrRCgsnXkGuLRC+GQM7ArLPkgoVw0GXM8TfI0bWyGWT7QYbHBzsyN5ajGA== +"@schematics/angular@12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-12.2.13.tgz#5bf3e7b699a42d7fd7f7aa12bbe4534e671e7201" + integrity sha512-TrigQ9TCmAedf1J5PSSSfTC+sScYrITeAUN8a9rlkjZNvff8hHVyQaiZmhqL+egKQL828mhkqpnFUDd4QsPBIw== dependencies: - "@angular-devkit/core" "11.2.13" - "@angular-devkit/schematics" "11.2.13" + "@angular-devkit/core" "12.2.13" + "@angular-devkit/schematics" "12.2.13" jsonc-parser "3.0.0" -"@schematics/update@0.1102.13": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.1102.13.tgz#d6e5a3df5bf22900f26dc76a8351651f99a655fb" - integrity sha512-lHym4eUhbvUORwRJQJzgVFjofnc9nB2f/Ef3NNEgn3OkvsxHWtPH8NCQy/tj6sBAsyqK2T88aO2nejU9fZgMog== - dependencies: - "@angular-devkit/core" "11.2.13" - "@angular-devkit/schematics" "11.2.13" - "@yarnpkg/lockfile" "1.1.0" - ini "2.0.0" - npm-package-arg "^8.0.0" - pacote "11.2.4" - semver "7.3.4" - semver-intersect "1.4.0" - "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -1705,6 +2680,11 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669" integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow== +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + "@turf/bbox@*", "@turf/bbox@^6.3.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5" @@ -2508,7 +3488,7 @@ adm-zip@^0.4.9: resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -2544,6 +3524,13 @@ ajv-errors@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== +ajv-formats@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.0.tgz#96eaf83e38d32108b66d82a9cb0cfa24886cdfeb" + integrity sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" @@ -2559,6 +3546,16 @@ ajv@6.12.6, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@8.6.2: + version "8.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" + integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: version "6.12.5" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" @@ -2569,6 +3566,16 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" + integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -2667,6 +3674,14 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + app-root-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" @@ -2841,6 +3856,19 @@ autoprefixer@10.2.4: normalize-range "^0.1.2" postcss-value-parser "^4.1.0" +autoprefixer@^9.6.1: + version "9.8.8" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" + integrity sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + picocolors "^0.2.1" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -2875,6 +3903,30 @@ babel-plugin-dynamic-import-node@^2.3.3: dependencies: object.assign "^4.1.0" +babel-plugin-polyfill-corejs2@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.3.tgz#6ed8e30981b062f8fe6aca8873a37ebcc8cc1c0f" + integrity sha512-NDZ0auNRzmAfE1oDDPW2JhzIMXUk+FFe2ICejmt5T4ocKgiQx3e0VCRx9NCAidcMtL2RUZaWtXnmjTCkx0tcbA== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.4" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.2.2: + version "0.2.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" + integrity sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + core-js-compat "^3.16.2" + +babel-plugin-polyfill-regenerator@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.3.tgz#2e9808f5027c4336c994992b48a4262580cb8d6d" + integrity sha512-JVE78oRZPKFIeUqFGrSORNzQnrDwZR16oiWeGM8ZyjBn2XAT5OjP+wXx5ESuo33nUsFUEJYjtklnsKbxW5L+7g== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.4" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -2895,7 +3947,7 @@ base64-js@^1.0.2: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== -base64-js@^1.3.1: +base64-js@^1.2.0, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -2952,7 +4004,7 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^4.0.3: +bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -3123,6 +4175,17 @@ browserslist@^4.0.0, browserslist@^4.9.1: escalade "^3.1.0" node-releases "^1.1.61" +browserslist@^4.12.0, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.6.4: + version "4.18.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" + integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== + dependencies: + caniuse-lite "^1.0.30001280" + electron-to-chromium "^1.3.896" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.1, browserslist@^4.16.6: version "4.16.6" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" @@ -3239,6 +4302,29 @@ cacache@15.0.5, cacache@^15.0.5: tar "^6.0.2" unique-filename "^1.1.1" +cacache@15.2.0: + version "15.2.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.2.0.tgz#73af75f77c58e72d8c630a7a2858cb18ef523389" + integrity sha512-uKoJSHmnrqXgthDFx/IU6ED/5xd+NNGe+Bb+kLZy7Ku4P+BaiWEUflAKPZ7eAzsYGcsAGASJZsybXp+quEcHTw== + dependencies: + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + cacache@^12.0.2: version "12.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" @@ -3260,6 +4346,30 @@ cacache@^12.0.2: unique-filename "^1.1.1" y18n "^4.0.0" +cacache@^15.2.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== + dependencies: + "@npmcli/fs" "^1.0.0" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -3305,6 +4415,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001135: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001146.tgz#c61fcb1474520c1462913689201fb292ba6f447c" integrity sha512-VAy5RHDfTJhpxnDdp2n40GPPLp3KqNrXz1QqFv4J64HvArKs8nuNMOWkB3ICOaBTU/Aj4rYAo/ytdQDDFF/Pug== +caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001280: + version "1.0.30001283" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001283.tgz#8573685bdae4d733ef18f78d44ba0ca5fe9e896b" + integrity sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg== + caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001219: version "1.0.30001228" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" @@ -3353,6 +4468,14 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -3373,6 +4496,21 @@ chardet@^0.7.0: optionalDependencies: fsevents "~2.1.2" +"chokidar@>=3.0.0 <4.0.0": + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" @@ -3596,6 +4734,11 @@ colord@^2.0.0: resolved "https://registry.yarnpkg.com/colord/-/colord-2.0.0.tgz#f8c19f2526b7dc5b22d6e57ef102f03a2a43a3d8" integrity sha512-WMDFJfoY3wqPZNpKUFdse3HhD5BHCbE9JCdxRzoVH+ywRITGOeWAHNkGEmyxLlErEpN9OLMWgdM9dWQtDk5dog== +colord@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.1.tgz#c961ea0efeb57c9f0f4834458f26cb9cc4a3f90e" + integrity sha512-4LBMSt09vR0uLnPVkOUBnmxgoaeN4ewRbx801wY/bXcltXfpR/G46OdWn96XpYmCWuYvO46aBZP4NgX8HpNAcw== + colorette@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" @@ -3628,7 +4771,7 @@ commander@^6.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== -commander@^7.1.0: +commander@^7.1.0, commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== @@ -3807,6 +4950,27 @@ copy-webpack-plugin@6.3.2: serialize-javascript "^5.0.1" webpack-sources "^1.4.3" +copy-webpack-plugin@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz#b71d21991599f61a4ee00ba79087b8ba279bbb59" + integrity sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw== + dependencies: + fast-glob "^3.2.5" + glob-parent "^6.0.0" + globby "^11.0.3" + normalize-path "^3.0.0" + p-limit "^3.1.0" + schema-utils "^3.0.0" + serialize-javascript "^6.0.0" + +core-js-compat@^3.15.0, core-js-compat@^3.16.2: + version "3.19.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.19.2.tgz#18066a3404a302433cb0aa8be82dd3d75c76e5c4" + integrity sha512-ObBY1W5vx/LFFMaL1P5Udo4Npib6fu+cMokeziWkA8Tns4FcDemKF5j9JvaI5JhdkW8EQJQGJN1EcrzmEwuAqQ== + dependencies: + browserslist "^4.18.1" + semver "7.0.0" + core-js-compat@^3.8.0: version "3.12.1" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.12.1.tgz#2c302c4708505fa7072b0adb5156d26f7801a18b" @@ -3815,6 +4979,11 @@ core-js-compat@^3.8.0: browserslist "^4.16.6" semver "7.0.0" +core-js@3.16.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.0.tgz#1d46fb33720bc1fa7f90d20431f36a5540858986" + integrity sha512-5+5VxRFmSf97nM8Jr2wzOwLqRo6zphH2aX+7KsAUONObyzakDNq2G/bgbhinxB4PoV9L3aXQYhiDKyIKWd2c8g== + core-js@3.8.3: version "3.8.3" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.3.tgz#c21906e1f14f3689f93abcc6e26883550dd92dd0" @@ -3880,6 +5049,18 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +critters@0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.12.tgz#32baa87526e053a41b67e19921673ed92264e2ab" + integrity sha512-ujxKtKc/mWpjrOKeaACTaQ1aP0O31M0ZPWhfl85jZF1smPU4Ivb9va5Ox2poif4zVJQQo0LCFlzGtEZAsCAPcw== + dependencies: + chalk "^4.1.0" + css-select "^4.1.3" + parse5 "^6.0.1" + parse5-htmlparser2-tree-adapter "^6.0.1" + postcss "^8.3.7" + pretty-bytes "^5.3.0" + critters@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.7.tgz#548b470360f4f3c51e622de3b7aa733c8f0b17bf" @@ -3919,6 +5100,13 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +css-blank-pseudo@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" + integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== + dependencies: + postcss "^7.0.5" + css-color-names@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -3936,6 +5124,14 @@ css-declaration-sorter@^6.0.3: dependencies: timsort "^0.3.0" +css-has-pseudo@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" + integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + css-line-break@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef" @@ -3961,6 +5157,33 @@ css-loader@5.0.1: schema-utils "^3.0.0" semver "^7.3.2" +css-loader@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.2.0.tgz#9663d9443841de957a3cb9bcea2eda65b3377071" + integrity sha512-/rvHfYRjIpymZblf49w8jYcRo2y9gj6rV8UroHGmBxKrIyGLokpycyKzp9OkitvqT29ZSpzJ0Ic7SpnJX3sC8g== + dependencies: + icss-utils "^5.1.0" + postcss "^8.2.15" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.0" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.1.0" + semver "^7.3.5" + +css-minimizer-webpack-plugin@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.0.2.tgz#8fadbdf10128cb40227bff275a4bb47412534245" + integrity sha512-B3I5e17RwvKPJwsxjjWcdgpU/zqylzK1bPVghcmpFHRL48DXiBgrtqz1BJsn68+t/zzaLp9kYAaEDvQ7GyanFQ== + dependencies: + cssnano "^5.0.6" + jest-worker "^27.0.2" + p-limit "^3.0.2" + postcss "^8.3.5" + schema-utils "^3.0.0" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + css-parse@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" @@ -3968,6 +5191,13 @@ css-parse@~2.0.0: dependencies: css "^2.0.0" +css-prefers-color-scheme@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" + integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== + dependencies: + postcss "^7.0.5" + css-select@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8" @@ -3979,6 +5209,17 @@ css-select@^3.1.2: domutils "^2.4.3" nth-check "^2.0.0" +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + css-selector-tokenizer@^0.7.1: version "0.7.3" resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" @@ -3987,7 +5228,7 @@ css-selector-tokenizer@^0.7.1: cssesc "^3.0.0" fastparse "^1.1.2" -css-tree@^1.1.2: +css-tree@^1.1.2, css-tree@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== @@ -4008,6 +5249,11 @@ css-what@^4.0.0: resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233" integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A== +css-what@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== + css@^2.0.0: version "2.2.4" resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" @@ -4034,6 +5280,16 @@ cssauron@^1.4.0: dependencies: through X.X.X +cssdb@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" + integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -4047,17 +5303,52 @@ cssnano-preset-default@^5.0.1: css-declaration-sorter "^6.0.3" cssnano-utils "^2.0.1" postcss-calc "^8.0.0" - postcss-colormin "^5.1.1" - postcss-convert-values "^5.0.1" + postcss-colormin "^5.1.1" + postcss-convert-values "^5.0.1" + postcss-discard-comments "^5.0.1" + postcss-discard-duplicates "^5.0.1" + postcss-discard-empty "^5.0.1" + postcss-discard-overridden "^5.0.1" + postcss-merge-longhand "^5.0.2" + postcss-merge-rules "^5.0.1" + postcss-minify-font-values "^5.0.1" + postcss-minify-gradients "^5.0.1" + postcss-minify-params "^5.0.1" + postcss-minify-selectors "^5.1.0" + postcss-normalize-charset "^5.0.1" + postcss-normalize-display-values "^5.0.1" + postcss-normalize-positions "^5.0.1" + postcss-normalize-repeat-style "^5.0.1" + postcss-normalize-string "^5.0.1" + postcss-normalize-timing-functions "^5.0.1" + postcss-normalize-unicode "^5.0.1" + postcss-normalize-url "^5.0.1" + postcss-normalize-whitespace "^5.0.1" + postcss-ordered-values "^5.0.1" + postcss-reduce-initial "^5.0.1" + postcss-reduce-transforms "^5.0.1" + postcss-svgo "^5.0.1" + postcss-unique-selectors "^5.0.1" + +cssnano-preset-default@^5.1.8: + version "5.1.8" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.8.tgz#7525feb1b72f7b06e57f55064cbdae341d79dea2" + integrity sha512-zWMlP0+AMPBVE852SqTrP0DnhTcTA2C1wAF92TKZ3Va+aUVqLIhkqKlnJIXXdqXD7RN+S1ujuWmNpvrJBiM/vg== + dependencies: + css-declaration-sorter "^6.0.3" + cssnano-utils "^2.0.1" + postcss-calc "^8.0.0" + postcss-colormin "^5.2.1" + postcss-convert-values "^5.0.2" postcss-discard-comments "^5.0.1" postcss-discard-duplicates "^5.0.1" postcss-discard-empty "^5.0.1" postcss-discard-overridden "^5.0.1" - postcss-merge-longhand "^5.0.2" - postcss-merge-rules "^5.0.1" + postcss-merge-longhand "^5.0.4" + postcss-merge-rules "^5.0.3" postcss-minify-font-values "^5.0.1" - postcss-minify-gradients "^5.0.1" - postcss-minify-params "^5.0.1" + postcss-minify-gradients "^5.0.3" + postcss-minify-params "^5.0.2" postcss-minify-selectors "^5.1.0" postcss-normalize-charset "^5.0.1" postcss-normalize-display-values "^5.0.1" @@ -4066,13 +5357,13 @@ cssnano-preset-default@^5.0.1: postcss-normalize-string "^5.0.1" postcss-normalize-timing-functions "^5.0.1" postcss-normalize-unicode "^5.0.1" - postcss-normalize-url "^5.0.1" + postcss-normalize-url "^5.0.3" postcss-normalize-whitespace "^5.0.1" - postcss-ordered-values "^5.0.1" - postcss-reduce-initial "^5.0.1" + postcss-ordered-values "^5.0.2" + postcss-reduce-initial "^5.0.2" postcss-reduce-transforms "^5.0.1" - postcss-svgo "^5.0.1" - postcss-unique-selectors "^5.0.1" + postcss-svgo "^5.0.3" + postcss-unique-selectors "^5.0.2" cssnano-utils@^2.0.1: version "2.0.1" @@ -4088,6 +5379,16 @@ cssnano@5.0.2: cssnano-preset-default "^5.0.1" is-resolvable "^1.1.0" +cssnano@^5.0.6: + version "5.0.12" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.12.tgz#2c083a1c786fc9dc2d5522bd3c0e331b7cd302ab" + integrity sha512-U38V4x2iJ3ijPdeWqUrEr4eKBB5PbEKsNP5T8xcik2Au3LeMtiMHX0i2Hu9k51FcKofNZumbrcdC6+a521IUHg== + dependencies: + cssnano-preset-default "^5.1.8" + is-resolvable "^1.1.0" + lilconfig "^2.0.3" + yaml "^1.10.2" + csso@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" @@ -4149,13 +5450,20 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@4, debug@4.3.1, debug@~4.3.1: +debug@4, debug@~4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== dependencies: ms "2.1.2" +debug@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + debug@^3.1.0, debug@^3.1.1: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -4177,6 +5485,13 @@ debug@^4.1.0, debug@^4.1.1: dependencies: ms "2.1.2" +debug@^4.3.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -4226,6 +5541,11 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -4301,10 +5621,10 @@ depd@^1.1.2, depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -dependency-graph@^0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" - integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== +dependency-graph@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" + integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== des.js@^1.0.0: version "1.0.1" @@ -4448,6 +5768,15 @@ domutils@^2.4.3: domelementtype "^2.2.0" domhandler "^4.2.0" +domutils@^2.6.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" @@ -4491,6 +5820,11 @@ electron-to-chromium@^1.3.723: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.737.tgz#196f2e9656f4f3c31930750e1899c091b72d36b5" integrity sha512-P/B84AgUSQXaum7a8m11HUsYL8tj9h/Pt5f7Hg7Ty6bm5DxlFq+e5+ouHUoNQMsKDJ7u4yGfI8mOErCmSH9wyg== +electron-to-chromium@^1.3.896: + version "1.4.5" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.5.tgz#912e8fd1645edee2f0f212558f40916eb538b1f9" + integrity sha512-YKaB+t8ul5crdh6OeqT2qXdxJGI0fAYb6/X8pDIyye+c3a7ndOCk5gVeKX+ABwivCGNS56vOAif3TN0qJMpEHw== + elliptic@^6.5.3: version "6.5.3" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" @@ -4580,7 +5914,7 @@ enhanced-resolve@^4.3.0: memory-fs "^0.5.0" tapable "^1.0.0" -enhanced-resolve@^5.8.3: +enhanced-resolve@^5.8.0, enhanced-resolve@^5.8.3: version "5.8.3" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== @@ -4603,11 +5937,6 @@ env-paths@^2.2.0: resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -err-code@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" - integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= - err-code@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" @@ -4662,6 +5991,11 @@ es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" +es-module-lexer@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.7.1.tgz#c2c8e0f46f2df06274cdaf0dd3f3b33e0a0b267d" + integrity sha512-MgtWFl5No+4S3TmhDmCz2ObFGm6lEpTnzbQi+Dd+pw4mlTIZTmM2iAs5gRlmx5zS9luzobCSBSI90JM/1/JgOw== + es-module-lexer@^0.9.0: version "0.9.3" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" @@ -4688,6 +6022,119 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +esbuild-android-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.8.tgz#c20e875c3c98164b1ffba9b28637bdf96f5e9e7c" + integrity sha512-AilbChndywpk7CdKkNSZ9klxl+9MboLctXd9LwLo3b0dawmOF/i/t2U5d8LM6SbT1Xw36F8yngSUPrd8yPs2RA== + +esbuild-darwin-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.8.tgz#f46e6b471ddbf62265234808a6a1aa91df18a417" + integrity sha512-b6sdiT84zV5LVaoF+UoMVGJzR/iE2vNUfUDfFQGrm4LBwM/PWXweKpuu6RD9mcyCq18cLxkP6w/LD/w9DtX3ng== + +esbuild-darwin-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.8.tgz#a991157a6013facd4f2e14159b7da52626c90154" + integrity sha512-R8YuPiiJayuJJRUBG4H0VwkEKo6AvhJs2m7Tl0JaIer3u1FHHXwGhMxjJDmK+kXwTFPriSysPvcobXC/UrrZCQ== + +esbuild-freebsd-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.8.tgz#301601d2e443ad458960e359b402a17d9500be9d" + integrity sha512-zBn6urrn8FnKC+YSgDxdof9jhPCeU8kR/qaamlV4gI8R3KUaUK162WYM7UyFVAlj9N0MyD3AtB+hltzu4cysTw== + +esbuild-freebsd-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.8.tgz#039a63acc12ec0892006c147ea221e55f9125a9f" + integrity sha512-pWW2slN7lGlkx0MOEBoUGwRX5UgSCLq3dy2c8RIOpiHtA87xAUpDBvZK10MykbT+aMfXc0NI2lu1X+6kI34xng== + +esbuild-linux-32@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.8.tgz#c537b67d7e694b60bfa2786581412838c6ba0284" + integrity sha512-T0I0ueeKVO/Is0CAeSEOG9s2jeNNb8jrrMwG9QBIm3UU18MRB60ERgkS2uV3fZ1vP2F8i3Z2e3Zju4lg9dhVmw== + +esbuild-linux-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.8.tgz#0092fc8a064001a777bfa0e3b425bb8be8f96e6a" + integrity sha512-Bm8SYmFtvfDCIu9sjKppFXzRXn2BVpuCinU1ChTuMtdKI/7aPpXIrkqBNOgPTOQO9AylJJc1Zw6EvtKORhn64w== + +esbuild-linux-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.8.tgz#5cd3f2bb924212971482e8dbc25c4afd09b28110" + integrity sha512-X4pWZ+SL+FJ09chWFgRNO3F+YtvAQRcWh0uxKqZSWKiWodAB20flsW/OWFYLXBKiVCTeoGMvENZS/GeVac7+tQ== + +esbuild-linux-arm@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.8.tgz#ad634f96bf2975536907aeb9fdb75a3194f4ddce" + integrity sha512-4/HfcC40LJ4GPyboHA+db0jpFarTB628D1ifU+/5bunIgY+t6mHkJWyxWxAAE8wl/ZIuRYB9RJFdYpu1AXGPdg== + +esbuild-linux-mips64le@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.8.tgz#57857edfebf9bf65766dc8be1637f2179c990572" + integrity sha512-o7e0D+sqHKT31v+mwFircJFjwSKVd2nbkHEn4l9xQ1hLR+Bv8rnt3HqlblY3+sBdlrOTGSwz0ReROlKUMJyldA== + +esbuild-linux-ppc64le@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.8.tgz#fdb82a059a5b86bb10fb42091b4ebcf488b9cd46" + integrity sha512-eZSQ0ERsWkukJp2px/UWJHVNuy0lMoz/HZcRWAbB6reoaBw7S9vMzYNUnflfL3XA6WDs+dZn3ekHE4Y2uWLGig== + +esbuild-netbsd-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.8.tgz#d7879e7123d3b2c04754ece8bd061aa6866deeff" + integrity sha512-gZX4kP7gVvOrvX0ZwgHmbuHczQUwqYppxqtoyC7VNd80t5nBHOFXVhWo2Ad/Lms0E8b+wwgI/WjZFTCpUHOg9Q== + +esbuild-openbsd-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.8.tgz#88b280b6cb0a3f6adb60abf27fc506c506a35cf0" + integrity sha512-afzza308X4WmcebexbTzAgfEWt9MUkdTvwIa8xOu4CM2qGbl2LanqEl8/LUs8jh6Gqw6WsicEK52GPrS9wvkcw== + +esbuild-sunos-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.8.tgz#229ae7c7703196a58acd0f0291ad9bebda815d63" + integrity sha512-mWPZibmBbuMKD+LDN23LGcOZ2EawMYBONMXXHmbuxeT0XxCNwadbCVwUQ/2p5Dp5Kvf6mhrlIffcnWOiCBpiVw== + +esbuild-wasm@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-wasm/-/esbuild-wasm-0.13.8.tgz#f34134c187ffcfc22d476e925917f70bab40f8b0" + integrity sha512-UbD+3nloiSpJWXTCInZQrqPe8Y+RLfDkY/5kEHiXsw/lmaEvibe69qTzQu16m5R9je/0bF7VYQ5jaEOq0z9lLA== + +esbuild-windows-32@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.8.tgz#892d093e32a21c0c9135e5a0ffdc380aeb70e763" + integrity sha512-QsZ1HnWIcnIEApETZWw8HlOhDSWqdZX2SylU7IzGxOYyVcX7QI06ety/aDcn437mwyO7Ph4RrbhB+2ntM8kX8A== + +esbuild-windows-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.8.tgz#7defd8d79ae3bb7e6f53b65a7190be7daf901686" + integrity sha512-76Fb57B9eE/JmJi1QmUW0tRLQZfGo0it+JeYoCDTSlbTn7LV44ecOHIMJSSgZADUtRMWT9z0Kz186bnaB3amSg== + +esbuild-windows-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.8.tgz#e59ae004496fd8a5ab67bfc7945a2e47480d6fb9" + integrity sha512-HW6Mtq5eTudllxY2YgT62MrVcn7oq2o8TAoAvDUhyiEmRmDY8tPwAhb1vxw5/cdkbukM3KdMYtksnUhF/ekWeg== + +esbuild@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.8.tgz#bd7cc51b881ab067789f88e17baca74724c1ec4f" + integrity sha512-A4af7G7YZLfG5OnARJRMtlpEsCkq/zHZQXewgPA864l9D6VjjbH1SuFYK/OSV6BtHwDGkdwyRrX0qQFLnMfUcw== + optionalDependencies: + esbuild-android-arm64 "0.13.8" + esbuild-darwin-64 "0.13.8" + esbuild-darwin-arm64 "0.13.8" + esbuild-freebsd-64 "0.13.8" + esbuild-freebsd-arm64 "0.13.8" + esbuild-linux-32 "0.13.8" + esbuild-linux-64 "0.13.8" + esbuild-linux-arm "0.13.8" + esbuild-linux-arm64 "0.13.8" + esbuild-linux-mips64le "0.13.8" + esbuild-linux-ppc64le "0.13.8" + esbuild-netbsd-64 "0.13.8" + esbuild-openbsd-64 "0.13.8" + esbuild-sunos-64 "0.13.8" + esbuild-windows-32 "0.13.8" + esbuild-windows-64 "0.13.8" + esbuild-windows-arm64 "0.13.8" + escalade@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" @@ -4761,6 +6208,11 @@ eve-raphael@0.5.0: resolved "https://registry.yarnpkg.com/eve-raphael/-/eve-raphael-0.5.0.tgz#17c754b792beef3fa6684d79cf5a47c63c4cda30" integrity sha1-F8dUt5K+7z+maE15z1pHxjxM2jA= +eventemitter-asyncresource@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz#734ff2e44bf448e627f7748f905d6bdd57bdb65b" + integrity sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ== + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -4928,6 +6380,17 @@ fast-glob@^3.1.1, fast-glob@^3.2.4: micromatch "^4.0.2" picomatch "^2.2.1" +fast-glob@^3.2.5: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@2.1.0, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -5059,6 +6522,11 @@ flatted@^2.0.1: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + "flot.curvedlines@git://github.com/MichaelZinsmaier/CurvedLines.git#master": version "1.1.1" resolved "git://github.com/MichaelZinsmaier/CurvedLines.git#22ed1fc2a6ccafc816c2d07b36027cc123825c4b" @@ -5134,15 +6602,6 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" -fs-extra@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" - integrity sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -5168,6 +6627,11 @@ fs-minipass@^2.0.0, fs-minipass@^2.1.0: dependencies: minipass "^3.0.0" +fs-monkey@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -5196,7 +6660,7 @@ fsevents@~2.1.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== -fsevents@~2.3.1: +fsevents@~2.3.1, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -5280,6 +6744,20 @@ glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" @@ -5297,6 +6775,18 @@ glob@7.1.6, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glo once "^1.3.0" path-is-absolute "^1.0.0" +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -5314,6 +6804,18 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" @@ -5459,6 +6961,20 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hdr-histogram-js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/hdr-histogram-js/-/hdr-histogram-js-2.0.1.tgz#ecb1ff2bcb6181c3e93ff4af9472c28c7e97284e" + integrity sha512-uPZxl1dAFnjUFHWLZmt93vUUvtHeaBay9nVNHu38SdOjMSF/4KqJUqa1Seuj08ptU1rEb6AHvB41X8n/zFZ74Q== + dependencies: + "@assemblyscript/loader" "^0.10.1" + base64-js "^1.2.0" + pako "^1.0.3" + +hdr-histogram-percentiles-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c" + integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw== + hex-color-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" @@ -5487,13 +7003,6 @@ hosted-git-info@^3.0.2: dependencies: lru-cache "^6.0.0" -hosted-git-info@^3.0.6: - version "3.0.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.8.tgz#6e35d4cc87af2c5f816e4cb9ce350ba87a3f370d" - integrity sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw== - dependencies: - lru-cache "^6.0.0" - hosted-git-info@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" @@ -5669,7 +7178,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -icss-utils@^5.0.0: +icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== @@ -5806,6 +7315,26 @@ inquirer@7.3.3: strip-ansi "^6.0.0" through "^2.3.6" +inquirer@8.1.2: + version "8.1.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.1.2.tgz#65b204d2cd7fb63400edd925dfe428bafd422e3d" + integrity sha512-DHLKJwLPNgkfwNmsuEUKSejJFbkv0FMO9SMiQbjI3n5NQuCrSIBqP66ggqyz2a6t2qEolKrMjhQ3+W/xXgUQ+Q== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.3.0" + run-async "^2.4.0" + rxjs "^7.2.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" @@ -5901,10 +7430,10 @@ is-color-stop@^1.1.0: rgb-regex "^1.0.1" rgba-regex "^1.0.0" -is-core-module@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" - integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== +is-core-module@^2.2.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== dependencies: has "^1.0.3" @@ -5950,6 +7479,11 @@ is-docker@^2.0.0: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== +is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -5998,6 +7532,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-in-browser@^1.0.2, is-in-browser@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" @@ -6104,6 +7645,11 @@ is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + is-what@^3.12.0: version "3.14.1" resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" @@ -6119,7 +7665,7 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.1: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -6256,7 +7802,7 @@ jest-worker@26.6.2, jest-worker@^26.5.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.0.6: +jest-worker@^27.0.2, jest-worker@^27.0.6: version "27.4.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.0.tgz#fa10dddc611cbb47a4153543dd16a0c7e7fd745c" integrity sha512-4WuKcUxtzxBoKOUFbt1MtTY9fJwPVD4aN/4Cgxee7OLetPZn5as2bjfZz98XSf2Zq1JFfhqPZpS+43BmWXKgCA== @@ -6346,6 +7892,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -6653,6 +8204,13 @@ leaflet@^1.7.1: resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.7.1.tgz#10d684916edfe1bf41d688a3b97127c0322a2a19" integrity sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw== +less-loader@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-10.0.1.tgz#c05aaba68d00400820275f21c2ad87cb9fa9923f" + integrity sha512-Crln//HpW9M5CbtdfWm3IO66Cvx1WhZQvNybXgfB2dD/6Sav9ppw+IWqs/FQKPBFO4B6X0X28Z0WNznshgwUzA== + dependencies: + klona "^2.0.4" + less-loader@7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-7.3.0.tgz#f9d6d36d18739d642067a05fb5bd70c8c61317e5" @@ -6687,6 +8245,14 @@ license-webpack-plugin@2.3.11: "@types/webpack-sources" "^0.1.5" webpack-sources "^1.2.0" +license-webpack-plugin@2.3.20: + version "2.3.20" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.20.tgz#f51fb674ca31519dbedbe1c7aabc036e5a7f2858" + integrity sha512-AHVueg9clOKACSHkhmEI+PCC9x8+qsQVuKECZD3ETxETK5h/PCv5/MUzyG1gm8OMcip/s1tcNxqo9Qb7WhjGsg== + dependencies: + "@types/webpack-sources" "^0.1.5" + webpack-sources "^1.2.0" + lie@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" @@ -6694,6 +8260,11 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" +lilconfig@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" + integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -6742,6 +8313,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -6762,7 +8338,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.21: +lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@~4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6774,6 +8350,14 @@ log-symbols@^4.0.0: dependencies: chalk "^4.0.0" +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + log4js@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" @@ -6846,13 +8430,13 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -make-fetch-happen@^8.0.9: - version "8.0.14" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" - integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== +make-fetch-happen@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== dependencies: agentkeepalive "^4.1.3" - cacache "^15.0.5" + cacache "^15.2.0" http-cache-semantics "^4.1.0" http-proxy-agent "^4.0.1" https-proxy-agent "^5.0.0" @@ -6863,8 +8447,9 @@ make-fetch-happen@^8.0.9: minipass-fetch "^1.3.2" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" + negotiator "^0.6.2" promise-retry "^2.0.1" - socks-proxy-agent "^5.0.0" + socks-proxy-agent "^6.0.0" ssri "^8.0.0" make-plural@^4.3.0: @@ -6874,6 +8459,13 @@ make-plural@^4.3.0: optionalDependencies: minimist "^1.2.0" +map-age-cleaner@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -6915,6 +8507,21 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +mem@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/mem/-/mem-8.1.1.tgz#cf118b357c65ab7b7e0817bdf00c8062297c0122" + integrity sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA== + dependencies: + map-age-cleaner "^0.1.3" + mimic-fn "^3.1.0" + +memfs@^3.2.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.0.tgz#8bc12062b973be6b295d4340595736a656f0a257" + integrity sha512-o/RfP0J1d03YwsAxyHxAYs2kyJp55AFkMazlFAZFR2I2IXkxiUTXRabJ6RmNNCQ83LAD2jy52Khj0m3OffpNdA== + dependencies: + fs-monkey "1.0.3" + memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -7004,6 +8611,14 @@ micromatch@^4.0.2: braces "^3.0.1" picomatch "^2.0.5" +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -7034,7 +8649,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.44.0" -mime-types@^2.1.27: +mime-types@^2.1.27, mime-types@^2.1.31: version "2.1.34" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== @@ -7056,6 +8671,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" + integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== + mini-css-extract-plugin@1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.5.tgz#252166e78879c106e0130f229d44e0cbdfcebed3" @@ -7065,6 +8685,13 @@ mini-css-extract-plugin@1.3.5: schema-utils "^3.0.0" webpack-sources "^1.1.0" +mini-css-extract-plugin@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.2.tgz#b3508191ea479388a4715018c99dd3e6dd40d2d2" + integrity sha512-ZmqShkn79D36uerdED+9qdo1ZYG8C1YsWvXu0UMJxurZnSdgz7gQKO2EGv8T55MhDqG3DYmGtizZNpM/UbTlcA== + dependencies: + schema-utils "^3.1.0" + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -7269,6 +8896,11 @@ nanoid@^3.1.22, nanoid@^3.1.23: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== +nanoid@^3.1.30: + version "3.1.30" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" + integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -7295,7 +8927,7 @@ needle@^2.5.2: iconv-lite "^0.4.4" sax "^1.2.4" -negotiator@0.6.2: +negotiator@0.6.2, negotiator@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== @@ -7388,16 +9020,34 @@ ngx-window-token@>=4.0.0: dependencies: tslib "^2.0.0" +nice-napi@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nice-napi/-/nice-napi-1.0.2.tgz#dc0ab5a1eac20ce548802fc5686eaa6bc654927b" + integrity sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA== + dependencies: + node-addon-api "^3.0.0" + node-gyp-build "^4.2.2" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-addon-api@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + node-forge@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== +node-gyp-build@^4.2.2: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" + integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + node-gyp@^7.1.0: version "7.1.2" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" @@ -7453,6 +9103,11 @@ node-releases@^1.1.71: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" @@ -7482,6 +9137,11 @@ normalize-url@^4.5.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + npm-bundled@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" @@ -7501,13 +9161,13 @@ npm-normalize-package-bin@^1.0.1: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.0.tgz#b5f6319418c3246a1c38e1a8fbaa06231bc5308f" - integrity sha512-/ep6QDxBkm9HvOhOg0heitSd7JHA1U7y1qhhlRlteYYAi9Pdb/ZV7FW5aHpkrpM8+P+4p/jjR8zCyKPBMBjSig== +npm-package-arg@8.1.5: + version "8.1.5" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" + integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== dependencies: - hosted-git-info "^3.0.6" - semver "^7.0.0" + hosted-git-info "^4.0.1" + semver "^7.3.4" validate-npm-package-name "^3.0.0" npm-package-arg@^8.0.0: @@ -7538,16 +9198,7 @@ npm-packlist@^2.1.4: npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -npm-pick-manifest@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.0.tgz#2befed87b0fce956790f62d32afb56d7539c022a" - integrity sha512-ygs4k6f54ZxJXrzT0x34NybRlLeZ4+6nECAIbr2i0foTnijtS1TJiyzpqtuUAJOps/hO0tNDr8fRV5g+BtRlTw== - dependencies: - npm-install-checks "^4.0.0" - npm-package-arg "^8.0.0" - semver "^7.0.0" - -npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: +npm-pick-manifest@6.1.1, npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== @@ -7557,14 +9208,12 @@ npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: npm-package-arg "^8.1.2" semver "^7.3.4" -npm-registry-fetch@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" - integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== +npm-registry-fetch@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" + integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== dependencies: - "@npmcli/ci-detect" "^1.0.0" - lru-cache "^6.0.0" - make-fetch-happen "^8.0.9" + make-fetch-happen "^9.0.1" minipass "^3.1.3" minipass-fetch "^1.3.0" minipass-json-stream "^1.0.1" @@ -7595,6 +9244,11 @@ nth-check@^2.0.0: dependencies: boolbase "^1.0.0" +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -7705,6 +9359,15 @@ open@7.4.0: is-docker "^2.0.0" is-wsl "^2.1.1" +open@8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/open/-/open-8.2.1.tgz#82de42da0ccbf429bc12d099dad2e0975e14e8af" + integrity sha512-rXILpcQlkF/QuFez2BJDf3GsqpjGKbkUUToAIGo9A0Q6ZkoSGogZJulrUdwRkrAsoQvoZsrjCYt8+zblOk7JQQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + open@^7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" @@ -7734,6 +9397,21 @@ ora@5.3.0: strip-ansi "^6.0.0" wcwidth "^1.0.1" +ora@5.4.1, ora@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" @@ -7751,6 +9429,11 @@ os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -7770,6 +9453,13 @@ p-limit@^3.0.2: dependencies: p-try "^2.0.0" +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -7808,15 +9498,15 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pacote@11.2.4: - version "11.2.4" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.2.4.tgz#dc7ca740a573ed86a3bf863511d22c1d413ec82f" - integrity sha512-GfTeVQGJ6WyBQbQD4t3ocHbyOmTQLmWjkCKSZPmKiGFKYKNUaM5U2gbLzUW8WG1XmS9yQFnsTFA0k3o1+q4klQ== +pacote@11.3.5: + version "11.3.5" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" + integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== dependencies: - "@npmcli/git" "^2.0.1" - "@npmcli/installed-package-contents" "^1.0.5" + "@npmcli/git" "^2.1.0" + "@npmcli/installed-package-contents" "^1.0.6" "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^1.3.0" + "@npmcli/run-script" "^1.8.2" cacache "^15.0.5" chownr "^2.0.0" fs-minipass "^2.1.0" @@ -7826,14 +9516,14 @@ pacote@11.2.4: npm-package-arg "^8.0.1" npm-packlist "^2.1.4" npm-pick-manifest "^6.0.0" - npm-registry-fetch "^9.0.0" - promise-retry "^1.1.1" - read-package-json-fast "^1.1.3" + npm-registry-fetch "^11.0.0" + promise-retry "^2.0.1" + read-package-json-fast "^2.0.1" rimraf "^3.0.2" - ssri "^8.0.0" + ssri "^8.0.1" tar "^6.1.0" -pako@~1.0.2, pako@~1.0.5: +pako@^1.0.3, pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -8007,11 +9697,26 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -8034,6 +9739,17 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +piscina@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/piscina/-/piscina-3.1.0.tgz#2333636865b6cb69c5a370bbc499a98cabcf3e04" + integrity sha512-KTW4sjsCD34MHrUbx9eAAbuUSpVj407hQSgk/6Epkg0pbRBmv4a3UX7Sr8wxm9xYqQLnsN4mFOjqGDzHAdgKQg== + dependencies: + eventemitter-asyncresource "^1.0.0" + hdr-histogram-js "^2.0.1" + hdr-histogram-percentiles-obj "^3.0.0" + optionalDependencies: + nice-napi "^1.0.2" + pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -8086,6 +9802,14 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +postcss-attribute-case-insensitive@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" + integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^6.0.2" + postcss-calc@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a" @@ -8094,6 +9818,48 @@ postcss-calc@^8.0.0: postcss-selector-parser "^6.0.2" postcss-value-parser "^4.0.2" +postcss-color-functional-notation@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" + integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-gray@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" + integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-color-hex-alpha@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" + integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== + dependencies: + postcss "^7.0.14" + postcss-values-parser "^2.0.1" + +postcss-color-mod-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" + integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-rebeccapurple@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" + integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + postcss-colormin@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.1.1.tgz#834d262f6021f832d9085e355f08ade288a92a1d" @@ -8103,6 +9869,16 @@ postcss-colormin@^5.1.1: colord "^2.0.0" postcss-value-parser "^4.1.0" +postcss-colormin@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.1.tgz#6e444a806fd3c578827dbad022762df19334414d" + integrity sha512-VVwMrEYLcHYePUYV99Ymuoi7WhKrMGy/V9/kTS0DkCoJYmmjdOMneyhzYUxcNgteKDVbrewOkSM7Wje/MFwxzA== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.1.0" + postcss-convert-values@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz#4ec19d6016534e30e3102fdf414e753398645232" @@ -8110,6 +9886,44 @@ postcss-convert-values@^5.0.1: dependencies: postcss-value-parser "^4.1.0" +postcss-convert-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059" + integrity sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-custom-media@^7.0.8: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" + integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== + dependencies: + postcss "^7.0.14" + +postcss-custom-properties@^8.0.11: + version "8.0.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" + integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== + dependencies: + postcss "^7.0.17" + postcss-values-parser "^2.0.1" + +postcss-custom-selectors@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" + integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-dir-pseudo-class@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" + integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + postcss-discard-comments@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe" @@ -8130,6 +9944,58 @@ postcss-discard-overridden@^5.0.1: resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6" integrity sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q== +postcss-double-position-gradients@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" + integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== + dependencies: + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-env-function@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" + integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-focus-visible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" + integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== + dependencies: + postcss "^7.0.2" + +postcss-focus-within@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" + integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== + dependencies: + postcss "^7.0.2" + +postcss-font-variant@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz#42d4c0ab30894f60f98b17561eb5c0321f502641" + integrity sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA== + dependencies: + postcss "^7.0.2" + +postcss-gap-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" + integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== + dependencies: + postcss "^7.0.2" + +postcss-image-set-function@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" + integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + postcss-import@14.0.0: version "14.0.0" resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.0.0.tgz#3ed1dadac5a16650bde3f4cdea6633b9c3c78296" @@ -8139,6 +10005,31 @@ postcss-import@14.0.0: read-cache "^1.0.0" resolve "^1.1.7" +postcss-import@14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.0.2.tgz#60eff77e6be92e7b67fe469ec797d9424cae1aa1" + integrity sha512-BJ2pVK4KhUyMcqjuKs9RijV5tatNzNa73e/32aBVE/ejYPe37iH+6vAu9WvqUkB5OAYgLHzbSvzHnorybJCm9g== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-initial@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.4.tgz#9d32069a10531fe2ecafa0b6ac750ee0bc7efc53" + integrity sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg== + dependencies: + postcss "^7.0.2" + +postcss-lab-function@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" + integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + postcss-loader@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.2.0.tgz#f6993ea3e0f46600fb3ee49bbd010448123a7db4" @@ -8150,6 +10041,29 @@ postcss-loader@4.2.0: schema-utils "^3.0.0" semver "^7.3.4" +postcss-loader@6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.1.1.tgz#58dd0a3accd9bc87cc52eff75244db578d11301a" + integrity sha512-lBmJMvRh1D40dqpWKr9Rpygwxn8M74U9uaCSeYGNKLGInbk9mXBt1ultHf2dH9Ghk6Ue4UXlXWwGMH9QdUJ5ug== + dependencies: + cosmiconfig "^7.0.0" + klona "^2.0.4" + semver "^7.3.5" + +postcss-logical@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" + integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== + dependencies: + postcss "^7.0.2" + +postcss-media-minmax@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" + integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== + dependencies: + postcss "^7.0.2" + postcss-merge-longhand@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz#277ada51d9a7958e8ef8cf263103c9384b322a41" @@ -8159,6 +10073,14 @@ postcss-merge-longhand@^5.0.2: postcss-value-parser "^4.1.0" stylehacks "^5.0.1" +postcss-merge-longhand@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" + integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== + dependencies: + postcss-value-parser "^4.1.0" + stylehacks "^5.0.1" + postcss-merge-rules@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.1.tgz#4ff61c5089d86845184a0f149e88d687028bef7e" @@ -8170,6 +10092,16 @@ postcss-merge-rules@^5.0.1: postcss-selector-parser "^6.0.5" vendors "^1.0.3" +postcss-merge-rules@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.3.tgz#b5cae31f53129812a77e3eb1eeee448f8cf1a1db" + integrity sha512-cEKTMEbWazVa5NXd8deLdCnXl+6cYG7m2am+1HzqH0EnTdy8fRysatkaXb2dEnR+fdaDxTvuZ5zoBdv6efF6hg== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + cssnano-utils "^2.0.1" + postcss-selector-parser "^6.0.5" + postcss-minify-font-values@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz#a90cefbfdaa075bd3dbaa1b33588bb4dc268addf" @@ -8186,6 +10118,15 @@ postcss-minify-gradients@^5.0.1: is-color-stop "^1.1.0" postcss-value-parser "^4.1.0" +postcss-minify-gradients@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz#f970a11cc71e08e9095e78ec3a6b34b91c19550e" + integrity sha512-Z91Ol22nB6XJW+5oe31+YxRsYooxOdFKcbOqY/V8Fxse1Y3vqlNRpi1cxCqoACZTQEhl+xvt4hsbWiV5R+XI9Q== + dependencies: + colord "^2.9.1" + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + postcss-minify-params@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz#371153ba164b9d8562842fdcd929c98abd9e5b6c" @@ -8197,6 +10138,16 @@ postcss-minify-params@^5.0.1: postcss-value-parser "^4.1.0" uniqs "^2.0.0" +postcss-minify-params@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.2.tgz#1b644da903473fbbb18fbe07b8e239883684b85c" + integrity sha512-qJAPuBzxO1yhLad7h2Dzk/F7n1vPyfHfCCh5grjGfjhi1ttCnq4ZXGIW77GSrEbh9Hus9Lc/e/+tB4vh3/GpDg== + dependencies: + alphanum-sort "^1.0.2" + browserslist "^4.16.6" + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + postcss-minify-selectors@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz#4385c845d3979ff160291774523ffa54eafd5a54" @@ -8233,6 +10184,13 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" +postcss-nesting@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" + integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg== + dependencies: + postcss "^7.0.2" + postcss-normalize-charset@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0" @@ -8293,6 +10251,15 @@ postcss-normalize-url@^5.0.1: normalize-url "^4.5.0" postcss-value-parser "^4.1.0" +postcss-normalize-url@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.3.tgz#42eca6ede57fe69075fab0f88ac8e48916ef931c" + integrity sha512-qWiUMbvkRx3kc1Dp5opzUwc7MBWZcSDK2yofCmdvFBCpx+zFPkxBC1FASQ59Pt+flYfj/nTZSkmF56+XG5elSg== + dependencies: + is-absolute-url "^3.0.3" + normalize-url "^6.0.1" + postcss-value-parser "^4.1.0" + postcss-normalize-whitespace@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz#b0b40b5bcac83585ff07ead2daf2dcfbeeef8e9a" @@ -8308,6 +10275,87 @@ postcss-ordered-values@^5.0.1: cssnano-utils "^2.0.1" postcss-value-parser "^4.1.0" +postcss-ordered-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044" + integrity sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ== + dependencies: + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-overflow-shorthand@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" + integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== + dependencies: + postcss "^7.0.2" + +postcss-page-break@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" + integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== + dependencies: + postcss "^7.0.2" + +postcss-place@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" + integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-preset-env@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5" + integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg== + dependencies: + autoprefixer "^9.6.1" + browserslist "^4.6.4" + caniuse-lite "^1.0.30000981" + css-blank-pseudo "^0.1.4" + css-has-pseudo "^0.10.0" + css-prefers-color-scheme "^3.1.1" + cssdb "^4.4.0" + postcss "^7.0.17" + postcss-attribute-case-insensitive "^4.0.1" + postcss-color-functional-notation "^2.0.1" + postcss-color-gray "^5.0.0" + postcss-color-hex-alpha "^5.0.3" + postcss-color-mod-function "^3.0.3" + postcss-color-rebeccapurple "^4.0.1" + postcss-custom-media "^7.0.8" + postcss-custom-properties "^8.0.11" + postcss-custom-selectors "^5.1.2" + postcss-dir-pseudo-class "^5.0.0" + postcss-double-position-gradients "^1.0.0" + postcss-env-function "^2.0.2" + postcss-focus-visible "^4.0.0" + postcss-focus-within "^3.0.0" + postcss-font-variant "^4.0.0" + postcss-gap-properties "^2.0.0" + postcss-image-set-function "^3.0.1" + postcss-initial "^3.0.0" + postcss-lab-function "^2.0.1" + postcss-logical "^3.0.0" + postcss-media-minmax "^4.0.0" + postcss-nesting "^7.0.0" + postcss-overflow-shorthand "^2.0.0" + postcss-page-break "^2.0.0" + postcss-place "^4.0.1" + postcss-pseudo-class-any-link "^6.0.0" + postcss-replace-overflow-wrap "^3.0.0" + postcss-selector-matches "^4.0.0" + postcss-selector-not "^4.0.0" + +postcss-pseudo-class-any-link@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" + integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + postcss-reduce-initial@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz#9d6369865b0f6f6f6b165a0ef5dc1a4856c7e946" @@ -8316,6 +10364,14 @@ postcss-reduce-initial@^5.0.1: browserslist "^4.16.0" caniuse-api "^3.0.0" +postcss-reduce-initial@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048" + integrity sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + postcss-reduce-transforms@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz#93c12f6a159474aa711d5269923e2383cedcf640" @@ -8324,6 +10380,38 @@ postcss-reduce-transforms@^5.0.1: cssnano-utils "^2.0.1" postcss-value-parser "^4.1.0" +postcss-replace-overflow-wrap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" + integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== + dependencies: + postcss "^7.0.2" + +postcss-selector-matches@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" + integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-not@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz#263016eef1cf219e0ade9a913780fc1f48204cbf" + integrity sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + postcss-selector-parser@^6.0.2: version "6.0.4" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3" @@ -8350,6 +10438,14 @@ postcss-svgo@^5.0.1: postcss-value-parser "^4.1.0" svgo "^2.3.0" +postcss-svgo@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30" + integrity sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA== + dependencies: + postcss-value-parser "^4.1.0" + svgo "^2.7.0" + postcss-unique-selectors@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz#3be5c1d7363352eff838bd62b0b07a0abad43bfc" @@ -8359,11 +10455,28 @@ postcss-unique-selectors@^5.0.1: postcss-selector-parser "^6.0.5" uniqs "^2.0.0" +postcss-unique-selectors@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1" + integrity sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== +postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" + integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + postcss@8.2.14: version "8.2.14" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.14.tgz#dcf313eb8247b3ce8078d048c0e8262ca565ad2b" @@ -8373,6 +10486,23 @@ postcss@8.2.14: nanoid "^3.1.22" source-map "^0.6.1" +postcss@8.3.6: + version "8.3.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" + integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A== + dependencies: + colorette "^1.2.2" + nanoid "^3.1.23" + source-map-js "^0.6.2" + +postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + postcss@^7.0.35: version "7.0.35" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" @@ -8391,6 +10521,15 @@ postcss@^8.1.4: nanoid "^3.1.23" source-map-js "^0.6.2" +postcss@^8.2.15, postcss@^8.3.5, postcss@^8.3.7: + version "8.4.4" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.4.tgz#d53d4ec6a75fd62557a66bb41978bf47ff0c2869" + integrity sha512-joU6fBsN6EIer28Lj6GDFoC/5yOZzLCfn0zHAn/MYXI7aPt4m4hK5KC5ovEZXy+lnCjmYIbQWngvju2ddyEr8Q== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + postinstall-prepare@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postinstall-prepare/-/postinstall-prepare-2.0.0.tgz#2a6867c1a13a05502aa115d0495efbbd778769cb" @@ -8428,14 +10567,6 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= -promise-retry@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" - integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= - dependencies: - err-code "^1.0.0" - retry "^0.10.0" - promise-retry@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" @@ -8842,14 +10973,6 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" -read-package-json-fast@^1.1.3: - version "1.2.2" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-1.2.2.tgz#fba77b0b0d66b1ab344e214cb0876577e749c423" - integrity sha512-39DbPJjkltEzfXJXB6D8/Ir3GFOU2YbSKa2HaB/Y3nKrc/zY+0XrALpID6/13ezWyzqvOHrBbR4t4cjQuTdBVQ== - dependencies: - json-parse-even-better-errors "^2.3.0" - npm-normalize-package-bin "^1.0.1" - read-package-json-fast@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz#2dcb24d9e8dd50fb322042c8c35a954e6cc7ac9e" @@ -8903,6 +11026,13 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + reflect-metadata@^0.1.2: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" @@ -8925,6 +11055,11 @@ regenerator-runtime@0.13.7, regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regenerator-runtime@0.13.9: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regenerator-transform@^0.14.2: version "0.14.5" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" @@ -9023,6 +11158,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -9071,12 +11211,12 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" - integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== +resolve@1.20.0, resolve@^1.14.2: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== dependencies: - is-core-module "^2.1.0" + is-core-module "^2.2.0" path-parse "^1.0.6" resolve@^1.1.7, resolve@^1.3.2: @@ -9099,11 +11239,6 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -retry@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" - integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= - retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -9189,13 +11324,20 @@ rxjs@6.6.3, rxjs@^6.5.3, rxjs@^6.6.0: dependencies: tslib "^1.9.0" -rxjs@~6.6.7: +rxjs@6.6.7, rxjs@~6.6.7: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" +rxjs@^7.2.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68" + integrity sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w== + dependencies: + tslib "~2.1.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -9229,6 +11371,14 @@ sass-loader@10.1.1: schema-utils "^3.0.0" semver "^7.3.2" +sass-loader@12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.1.0.tgz#b73324622231009da6fba61ab76013256380d201" + integrity sha512-FVJZ9kxVRYNZTIe2xhw93n3xJNYZADr+q69/s98l9nTCrWASo+DR2Ot0s5xTKQDDEosUkatsGeHxcH4QBp5bSg== + dependencies: + klona "^2.0.4" + neo-async "^2.6.2" + sass@1.32.6: version "1.32.6" resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.6.tgz#e3646c8325cd97ff75a8a15226007f3ccd221393" @@ -9236,6 +11386,13 @@ sass@1.32.6: dependencies: chokidar ">=2.0.0 <4.0.0" +sass@1.36.0: + version "1.36.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.36.0.tgz#5912ef9d5d16714171ba11cb17edb274c4bbc07e" + integrity sha512-fQzEjipfOv5kh930nu3Imzq3ie/sGDc/4KtQMJlt7RRdrkQSfe37Bwi/Rf/gfuYHsIuE1fIlDMvpyMcEwjnPvg== + dependencies: + chokidar ">=3.0.0 <4.0.0" + saucelabs@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" @@ -9338,13 +11495,6 @@ semver-dsl@^1.0.1: dependencies: semver "^5.3.0" -semver-intersect@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/semver-intersect/-/semver-intersect-1.4.0.tgz#bdd9c06bedcdd2fedb8cd352c3c43ee8c61321f3" - integrity sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ== - dependencies: - semver "^5.0.0" - semver@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -9357,12 +11507,19 @@ semver@7.3.4: dependencies: lru-cache "^6.0.0" -semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +semver@7.3.5, semver@^7.3.4, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -9372,13 +11529,6 @@ semver@^7.0.0, semver@^7.1.1, semver@^7.3.2: resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== -semver@^7.3.4, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -9614,16 +11764,16 @@ sockjs@^0.3.21: uuid "^3.4.0" websocket-driver "^0.7.4" -socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== +socks-proxy-agent@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" + integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== dependencies: - agent-base "6" - debug "4" - socks "^2.3.3" + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" -socks@^2.3.3: +socks@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== @@ -9641,6 +11791,11 @@ source-map-js@^0.6.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== +source-map-js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" + integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== + source-map-loader@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-1.1.3.tgz#7dbc2fe7ea09d3e43c51fd9fc478b7f016c1f820" @@ -9653,6 +11808,15 @@ source-map-loader@1.1.3: source-map "^0.6.1" whatwg-mimetype "^2.3.0" +source-map-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.0.tgz#f2a04ee2808ad01c774dea6b7d2639839f3b3049" + integrity sha512-GKGWqWvYr04M7tn8dryIWvb0s8YM41z82iQv01yBtIylgxax0CwvSy6gc2Y02iuXwEfGWRlMicH0nvms9UZphw== + dependencies: + abab "^2.0.5" + iconv-lite "^0.6.2" + source-map-js "^0.6.2" + source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -9715,7 +11879,7 @@ source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: +sourcemap-codec@1.4.8, sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== @@ -9806,6 +11970,13 @@ ssri@^8.0.0: dependencies: minipass "^3.1.1" +ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" @@ -9976,6 +12147,11 @@ style-loader@2.0.0: loader-utils "^2.0.0" schema-utils "^3.0.0" +style-loader@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.2.1.tgz#63cb920ec145c8669e9a50e92961452a1ef5dcde" + integrity sha512-1k9ZosJCRFaRbY6hH49JFlRB0fVSbmnyq1iTPjNxUmGVjBNEmwrrHPenhlp+Lgo51BojHSf6pl2FcqYaN3PfVg== + stylehacks@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" @@ -9995,6 +12171,15 @@ stylus-loader@4.3.3: normalize-path "^3.0.0" schema-utils "^3.0.0" +stylus-loader@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-6.1.0.tgz#7a3a719a27cb2b9617896d6da28fda94c3ed9762" + integrity sha512-qKO34QCsOtSJrXxQQmXsPeaVHh6hMumBAFIoJTcsSr2VzrA6o/CW9HCGR8spCjzJhN8oKQHdj/Ytx0wwXyElkw== + dependencies: + fast-glob "^3.2.5" + klona "^2.0.4" + normalize-path "^3.0.0" + stylus@0.54.8: version "0.54.8" resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147" @@ -10055,15 +12240,28 @@ svgo@^2.3.0: csso "^4.2.0" stable "^0.1.8" +svgo@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + symbol-observable@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -symbol-observable@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-3.0.0.tgz#eea8f6478c651018e059044268375c408c15c533" - integrity sha512-6tDOXSHiVjuCaasQSWTmHUWn4PuG7qa3+1WT031yTc/swT7+rLiw3GOrFxaH1E3lLP09dH3bVuVDf2gK5rxG3Q== +symbol-observable@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== systemjs@0.21.5: version "0.21.5" @@ -10124,6 +12322,18 @@ terser-webpack-plugin@4.2.3: terser "^5.3.4" webpack-sources "^1.4.3" +terser-webpack-plugin@5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz#c369cf8a47aa9922bd0d8a94fe3d3da11a7678a1" + integrity sha512-C2WkFwstHDhVEmsmlCxrXUtVklS+Ir1A7twrYzrDrQQOIMOaVAYykaoo/Aq1K0QRkMoY2hhvDQY1cm4jnIMFwA== + dependencies: + jest-worker "^27.0.2" + p-limit "^3.1.0" + schema-utils "^3.0.0" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.0" + terser-webpack-plugin@^1.4.3: version "1.4.5" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" @@ -10159,6 +12369,15 @@ terser@5.5.1: source-map "~0.7.2" source-map-support "~0.5.19" +terser@5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784" + integrity sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.19" + terser@^4.1.2: version "4.8.0" resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" @@ -10177,7 +12396,7 @@ terser@^5.3.4: source-map "~0.7.2" source-map-support "~0.5.19" -terser@^5.7.2: +terser@^5.7.0, terser@^5.7.2: version "5.10.0" resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== @@ -10348,11 +12567,16 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@2.1.0: +tslib@2.1.0, tslib@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + tslib@^1.10.0, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: version "1.14.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.0.tgz#d624983f3e2c5e0b55307c3dd6c86acd737622c6" @@ -10444,10 +12668,10 @@ typescript@4.1.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.5.tgz#123a3b214aaff3be32926f0d8f1f6e704eb89a72" integrity sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA== -typescript@~4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5" - integrity sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg== +typescript@4.3.5, typescript@~4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" + integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== ua-parser-js@^0.7.23: version "0.7.28" @@ -10511,15 +12735,6 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" -universal-analytics@0.4.23: - version "0.4.23" - resolved "https://registry.yarnpkg.com/universal-analytics/-/universal-analytics-0.4.23.tgz#d915e676850c25c4156762471bdd7cf2eaaca8ac" - integrity sha512-lgMIH7XBI6OgYn1woDEmxhGdj8yDefMKg7GkWdeATAlQZFrMrNyxSkpDzY57iY0/6fdlzTbBV03OawvvzG+q7A== - dependencies: - debug "^4.1.1" - request "^2.88.2" - uuid "^3.0.0" - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -10613,7 +12828,7 @@ uuid@8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^3.0.0, uuid@^3.3.2, uuid@^3.4.0: +uuid@^3.3.2, uuid@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -10679,7 +12894,7 @@ watchpack@^1.7.4: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.0" -watchpack@^2.3.0: +watchpack@^2.2.0, watchpack@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.0.tgz#a41bca3da6afaff31e92a433f4c856a0c25ea0c4" integrity sha512-MnN0Q1OsvB/GGHETrFeZPQaOelWh/7O+EiFlj8sM9GPjtQkis7k01aAxrg/18kTfoIVcLL+haEVFlXDaSRwKRw== @@ -10737,6 +12952,18 @@ webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2: range-parser "^1.2.1" webpack-log "^2.0.0" +webpack-dev-middleware@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.0.0.tgz#0abe825275720e0a339978aea5f0b03b140c1584" + integrity sha512-9zng2Z60pm6A98YoRcA0wSxw1EYn7B7y5owX/Tckyt9KGyULTkLtiavjaXlWqOMkM0YtqGgL3PvMOFgyFLq8vw== + dependencies: + colorette "^1.2.2" + mem "^8.1.1" + memfs "^3.2.2" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^3.0.0" + webpack-dev-server@3.11.2: version "3.11.2" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708" @@ -10792,6 +13019,14 @@ webpack-merge@5.7.3, webpack-merge@^5.7.3: clone-deep "^4.0.1" wildcard "^2.0.0" +webpack-merge@5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + webpack-sources@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac" @@ -10808,7 +13043,7 @@ webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack- source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^3.2.2: +webpack-sources@^3.2.0, webpack-sources@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw== @@ -10849,6 +13084,36 @@ webpack@4.44.2: watchpack "^1.7.4" webpack-sources "^1.4.1" +webpack@5.50.0: + version "5.50.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.50.0.tgz#5562d75902a749eb4d75131f5627eac3a3192527" + integrity sha512-hqxI7t/KVygs0WRv/kTgUW8Kl3YC81uyWQSo/7WUs5LsuRw0htH/fCwbVBGCuiX/t4s7qzjXFcf41O8Reiypag== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.8.0" + es-module-lexer "^0.7.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.4" + json-parse-better-errors "^1.0.2" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.2.0" + webpack-sources "^3.2.0" + webpack@^5.64.4: version "5.64.4" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.64.4.tgz#e1454b6a13009f57cc2c78e08416cd674622937b" @@ -11030,7 +13295,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.0: +yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== @@ -11089,7 +13354,7 @@ yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.1.1, yargs@^16.2.0: +yargs@^16.1.1: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -11102,11 +13367,29 @@ yargs@^16.1.1, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.0.0: + version "17.2.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea" + integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zone.js@~0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.3.tgz#3e5e4da03c607c9dcd92e37dd35687a14a140c16" From 3992ddcadfc7d5cdbf5b220cfcdcde7b29d5a7f8 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:53:21 +0200 Subject: [PATCH 276/303] Update flex-layout and datepicker --- ui-ngx/package.json | 6 +++--- ui-ngx/yarn.lock | 25 +++++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 06ec15ace2..09daa6bc04 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -18,7 +18,7 @@ "@angular/common": "^12.2.13", "@angular/compiler": "^12.2.13", "@angular/core": "^12.2.13", - "@angular/flex-layout": "^11.0.0-beta.33", + "@angular/flex-layout": "^12.0.0-beta.35", "@angular/forms": "^12.2.13", "@angular/material": "^11.2.13", "@angular/platform-browser": "^12.2.13", @@ -30,7 +30,7 @@ "@flowjs/ngx-flow": "~0.4.6", "@geoman-io/leaflet-geoman-free": "^2.11.3", "@juggle/resize-observer": "^3.3.1", - "@mat-datetimepicker/core": "~6.0.2", + "@mat-datetimepicker/core": "~7.0.1", "@material-ui/core": "^4.11.4", "@material-ui/icons": "^4.11.2", "@material-ui/pickers": "^3.3.10", @@ -148,4 +148,4 @@ "resolutions": { "lodash": "~4.17.21" } -} \ No newline at end of file +} diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index b1b280a8bc..3b3bb0d055 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -356,12 +356,12 @@ dependencies: tslib "^2.2.0" -"@angular/flex-layout@^11.0.0-beta.33": - version "11.0.0-beta.33" - resolved "https://registry.yarnpkg.com/@angular/flex-layout/-/flex-layout-11.0.0-beta.33.tgz#c2d08f90164701b66a62b8c4365b4e22c1e95789" - integrity sha512-unfhw3abZuKtdwQicRStHCYGbANPTHYg4WNRQk/RC5Mxq+4WOp4Q8HI7GqRHCGUYDCGUP7w1sU/oDt8f09nM8w== +"@angular/flex-layout@^12.0.0-beta.35": + version "12.0.0-beta.35" + resolved "https://registry.yarnpkg.com/@angular/flex-layout/-/flex-layout-12.0.0-beta.35.tgz#b52c3c82608cbb92a119f8dcde2a5b98186fe558" + integrity sha512-nPi2MGDFuCacwWHqxF/G7lUJd2X99HbLjjUvKXnyLwyCIVgH1sfS52su2wYbVYWJRqAVAB2/VMlrtW8Khr8hDA== dependencies: - tslib "^2.0.0" + tslib "^2.1.0" "@angular/forms@^12.2.13": version "12.2.13" @@ -2442,12 +2442,12 @@ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0" integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== -"@mat-datetimepicker/core@~6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@mat-datetimepicker/core/-/core-6.0.2.tgz#c4f00fee4780e116ad0b685dcdf1014ad81301c5" - integrity sha512-cBzbg9GNOcV3eyhXa/44TTlBIy0t4Qgp1agSrhUoMucnFzhlIcF0LrUswOOQaldXDw1FQUQE5VQz4KSFjac8+g== +"@mat-datetimepicker/core@~7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@mat-datetimepicker/core/-/core-7.0.1.tgz#dac547195f25d448cfeaa11e0384f59639065c5f" + integrity sha512-lTYFJYstVb5l5JuNwVVZeyMaDtkZIq+eKycUa+5aJBAPhjapwdJx6lHiaZODgydRNtzdw79pQcB00mufguv3ew== dependencies: - tslib "^2.0.0" + tslib "^2.3.0" "@material-ui/core@^4.11.4": version "4.11.4" @@ -12587,6 +12587,11 @@ tslib@^2.0.0, tslib@^2.0.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.2.tgz#462295631185db44b21b1ea3615b63cd1c038242" integrity sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg== +tslib@^2.1.0, tslib@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tslib@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" From ac39ceab969bfe244a429585a12bac9fecd74368 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:57:35 +0200 Subject: [PATCH 277/303] Update angular material 12 --- ui-ngx/package.json | 6 +-- ui-ngx/src/theme.scss | 106 +++++++++++++++++++++--------------------- ui-ngx/yarn.lock | 20 ++++---- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 09daa6bc04..44cfd99ff5 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -14,13 +14,13 @@ "private": true, "dependencies": { "@angular/animations": "^12.2.13", - "@angular/cdk": "^11.2.13", + "@angular/cdk": "^12.2.13", "@angular/common": "^12.2.13", "@angular/compiler": "^12.2.13", "@angular/core": "^12.2.13", "@angular/flex-layout": "^12.0.0-beta.35", "@angular/forms": "^12.2.13", - "@angular/material": "^11.2.13", + "@angular/material": "^12.2.13", "@angular/platform-browser": "^12.2.13", "@angular/platform-browser-dynamic": "^12.2.13", "@angular/router": "^12.2.13", @@ -148,4 +148,4 @@ "resolutions": { "lodash": "~4.17.21" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/theme.scss b/ui-ngx/src/theme.scss index 25e1131e63..fdad632bee 100644 --- a/ui-ngx/src/theme.scss +++ b/ui-ngx/src/theme.scss @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import '~@angular/material/theming'; +@use '~@angular/material' as mat; @import '~@mat-datetimepicker/core/datetimepicker/datetimepicker-theme.scss'; @import './scss/constants'; -@include mat-core(); +@include mat.core(); $tb-primary-color: #305680; $tb-secondary-color: #527dad; @@ -41,39 +41,39 @@ $tb-mat-indigo: ( A400: #3d5afe, A700: #304ffe, contrast: ( - 50: $dark-primary-text, - 100: $dark-primary-text, - 200: $dark-primary-text, - 300: $light-primary-text, - 400: $light-primary-text, - 500: $light-primary-text, - 600: $light-primary-text, - 700: $light-primary-text, - 800: $light-primary-text, - 900: $light-primary-text, - A100: $dark-primary-text, - A200: $light-primary-text, - A400: $light-primary-text, - A700: $light-primary-text, + 50: rgba(black, 0.87), + 100: rgba(black, 0.87), + 200: rgba(black, 0.87), + 300: white, + 400: white, + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(black, 0.87), + A200: white, + A400: white, + A700: white, ) ); -$tb-primary: mat-palette($tb-mat-indigo); -$tb-accent: mat-palette($mat-deep-orange); +$tb-primary: mat.define-palette($tb-mat-indigo); +$tb-accent: mat.define-palette(mat.$deep-orange-palette); -$background: (background: map_get($mat-grey, 200)); +$background: (background: map_get(mat.$grey-palette, 200)); -$tb-theme-background: map_merge($mat-light-theme-background, $background); +$tb-theme-background: map_merge(mat.$light-theme-background-palette, $background); -$tb-mat-theme: mat-light-theme( +$tb-mat-theme: mat.define-light-theme( $tb-primary, $tb-accent ); $tb-theme: map_merge($tb-mat-theme, (background: $tb-theme-background)); -$primary: mat-color($tb-primary); -$accent: mat-color($tb-accent); +$primary: mat.get-color-from-palette($tb-primary); +$accent: mat.get-color-from-palette($tb-accent); $tb-dark-mat-indigo: ( 50: #e8eaf6, @@ -91,24 +91,24 @@ $tb-dark-mat-indigo: ( A400: #3d5afe, A700: #304ffe, contrast: ( - 50: $dark-primary-text, - 100: $dark-primary-text, - 200: $dark-primary-text, - 300: $dark-primary-text, - 400: $dark-primary-text, + 50: rgba(black, 0.87), + 100: rgba(black, 0.87), + 200: rgba(black, 0.87), + 300: rgba(black, 0.87), + 400: rgba(black, 0.87), 500: map_get($tb-mat-indigo, 900), - 600: $light-primary-text, - 700: $light-primary-text, - 800: $light-primary-text, - 900: $light-primary-text, - A100: $dark-primary-text, - A200: $dark-primary-text, - A400: $dark-primary-text, - A700: $dark-primary-text, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(black, 0.87), + A200: rgba(black, 0.87), + A400: rgba(black, 0.87), + A700: rgba(black, 0.87), ) ); -$tb-dark-primary: mat-palette($tb-dark-mat-indigo); +$tb-dark-primary: mat.define-palette($tb-dark-mat-indigo); $tb-dark-theme-background: ( status-bar: black, @@ -119,22 +119,22 @@ $tb-dark-theme-background: ( dialog: map_get($tb-dark-mat-indigo, 800), disabled-button: rgba(white, 0.12), raised-button: map-get($tb-dark-mat-indigo, 50), - focused-button: $light-focused, + focused-button: rgba(white, 0.12), selected-button: map_get($tb-dark-mat-indigo, 900), selected-disabled-button: map_get($tb-dark-mat-indigo, 800), disabled-button-toggle: black, unselected-chip: map_get($tb-dark-mat-indigo, 700), disabled-list-option: black, - tooltip: map_get($mat-grey, 700), + tooltip: map_get(mat.$grey-palette, 700), ); -@function get-tb-dark-theme($primary, $accent, $warn: mat-palette($mat-red)) { +@function get-tb-dark-theme($primary, $accent, $warn: mat.define-palette(mat.$red-palette)) { @return ( primary: $primary, accent: $accent, warn: $warn, is-dark: true, - foreground: $mat-dark-theme-foreground, + foreground: mat.$dark-theme-foreground-palette, background: $tb-dark-theme-background, ); } @@ -153,8 +153,8 @@ $tb-dark-theme: get-tb-dark-theme( mat-fab-toolbar { .mat-fab-toolbar-background { - background: mat-color($background, app-bar); - color: mat-color($foreground, text); + background: mat.get-color-from-palette($background, app-bar); + color: mat.get-color-from-palette($foreground, text); } &.mat-primary { .mat-fab-toolbar-background { @@ -175,8 +175,8 @@ $tb-dark-theme: get-tb-dark-theme( } @mixin _mat-toolbar-inverse-color($palette) { - background: mat-color($palette, default-contrast); - color: $dark-primary-text; + background: mat.get-color-from-palette($palette, default-contrast); + color: rgba(black, 0.87); } @mixin mat-fab-toolbar-inverse-theme($theme) { @@ -188,8 +188,8 @@ $tb-dark-theme: get-tb-dark-theme( mat-fab-toolbar { .mat-fab-toolbar-background { - background: mat-color($background, app-bar); - color: mat-color($foreground, text); + background: mat.get-color-from-palette($background, app-bar); + color: mat.get-color-from-palette($foreground, text); } &.mat-primary { .mat-fab-toolbar-background { @@ -201,15 +201,15 @@ $tb-dark-theme: get-tb-dark-theme( @include _mat-toolbar-inverse-color($primary); button.mat-icon-button { mat-icon { - color: mat-color($primary); + color: mat.get-color-from-palette($primary); } } } } .mat-fab { &.mat-primary { - background: mat-color($primary, default-contrast); - color: mat-color($primary); + background: mat.get-color-from-palette($primary, default-contrast); + color: mat.get-color-from-palette($primary); } } } @@ -221,7 +221,7 @@ $tb-dark-theme: get-tb-dark-theme( mat-toolbar{ &.mat-hue-3 { - background-color: mat-color($primary, 'A100'); + background-color: mat.get-color-from-palette($primary, 'A100'); } } @@ -233,12 +233,12 @@ $tb-dark-theme: get-tb-dark-theme( } .tb-default { - @include angular-material-theme($tb-theme); + @include mat.all-component-themes($tb-theme); @include mat-datetimepicker-theme($tb-theme); @include tb-components-theme($tb-theme); } .tb-dark { - @include angular-material-theme($tb-dark-theme); + @include mat.all-component-themes($tb-dark-theme); } diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 3b3bb0d055..9aae7fabc0 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -271,12 +271,12 @@ dependencies: tslib "^2.2.0" -"@angular/cdk@^11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-11.2.13.tgz#d54c9187e3b8cf3f8ba190b1edddc08ed2b740de" - integrity sha512-FkE4iCwoLbQxLDUOjV1I7M/6hmpyb7erAjEdWgch7nGRNxF1hqX5Bqf1lvLFKPNCbx5NRI5K7YVAdIUQUR8vug== +"@angular/cdk@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-12.2.13.tgz#1fdbe814adfd6b4ff906c6d9c4c6df07b83f09d8" + integrity sha512-zSKRhECyFqhingIeyRInIyTvYErt4gWo+x5DQr0b7YLUbU8DZSwWnG4w76Ke2s4U8T7ry1jpJBHoX/e8YBpGMg== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" optionalDependencies: parse5 "^5.0.0" @@ -375,12 +375,12 @@ resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.2.13.tgz#326045a328f8a962287037d7a85be8120074421c" integrity sha512-jb9s3IJuWNKTRcM90NOwvMfiy85nnKfTxxLVn8/QFMO6+Ps/hsVZNp+W/TmAEDvCkon+9q0O4hwa4MY1m/Dlkw== -"@angular/material@^11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular/material/-/material-11.2.13.tgz#99960316d3ce58aac7497d7bb8b0c05468f502b9" - integrity sha512-FqFdGSkOtqsmeLyTSousodDGUy2NqbtxCIKv2rwbsIRwHNKB0KpR/UQhA2gMRuGa5hxhMJ0DW0Tf9neMRuLCTg== +"@angular/material@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/material/-/material-12.2.13.tgz#7f92f95002a2abaa8bb115ca8f0809bdc3f7d3fc" + integrity sha512-6g2GyN4qp2D+DqY2AwrQuPB3cd9gybvQVXvNRbTPXEulHr+LgGei00ySdFHFp6RvdGSMZ4i3LM1Fq3VkFxhCfQ== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" "@angular/platform-browser-dynamic@^12.2.13": version "12.2.13" From abe7055b8b84f4a1fbc1b2e12463e9503aea3c7c Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 10:00:06 +0200 Subject: [PATCH 278/303] Remove ie11 support --- ui-ngx/src/.browserslistrc | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/.browserslistrc b/ui-ngx/src/.browserslistrc index 0209813ebf..6ef5d1aee4 100644 --- a/ui-ngx/src/.browserslistrc +++ b/ui-ngx/src/.browserslistrc @@ -8,4 +8,3 @@ last 2 versions Firefox ESR not dead -IE 11 From 935770e1a799e3e0f2ca8b2e6fa62ddc2d7b2af1 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 30 Nov 2021 11:16:51 +0200 Subject: [PATCH 279/303] refactored --- .../lwm2m/server/client/LwM2mClientContextImpl.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 823f16a99a..e2b05847f7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -22,10 +22,7 @@ import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Lazy; -import org.springframework.context.event.EventListener; -import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.data.PowerMode; @@ -36,6 +33,7 @@ import org.thingsboard.server.common.transport.TransportDeviceProfileCache; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; @@ -90,8 +88,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private final Map profiles = new ConcurrentHashMap<>(); - @EventListener(ApplicationReadyEvent.class) - @Order(Integer.MAX_VALUE - 1) + @AfterStartUp(order = Integer.MAX_VALUE - 1) public void init() { String nodeId = context.getNodeId(); Set fetchedClients = clientStore.getAll(); From 61e7dc4a90a104d6c04dd7649c10ed2167ae3961 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 23 Nov 2021 16:08:00 +0200 Subject: [PATCH 280/303] fixed lwm2m device or profile update notifications --- .../uplink/DefaultLwM2MUplinkMsgHandler.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 7a2d27d548..dc96b1a9d2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -378,9 +378,13 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl List clients = clientContext.getLwM2mClients() .stream().filter(e -> e.getProfileId() != null) .filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList()); - clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile)); + clients.forEach(client -> { + this.securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); + client.onDeviceProfileUpdate(deviceProfile); + }); if (clients.size() > 0) { - this.onDeviceProfileUpdate(clients, deviceProfile); + var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); + this.onDeviceProfileUpdate(clients, oldProfile, deviceProfile); } } catch (Exception e) { log.warn("[{}] failed to update profile: {}", deviceProfile.getId(), deviceProfile); @@ -392,6 +396,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl try { LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId()); if (client != null) { + this.securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); this.onDeviceUpdate(client, device, deviceProfileOpt); } } catch (Exception e) { @@ -645,7 +650,8 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional deviceProfileOpt) { - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile)); + var oldProfile = clientContext.getProfile(lwM2MClient.getProfileId()); + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), oldProfile, deviceProfile)); lwM2MClient.onDeviceUpdate(device, deviceProfileOpt); } @@ -754,8 +760,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } //TODO: review and optimize the logic to minimize number of the requests to device. - private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { - var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); + private void onDeviceProfileUpdate(List clients, Lwm2mDeviceProfileTransportConfiguration oldProfile, DeviceProfile deviceProfile) { if (clientContext.profileUpdate(deviceProfile) != null) { // #1 TelemetryMappingConfiguration oldTelemetryParams = oldProfile.getObserveAttr(); From d024c69a0cfcd37c2d39d2e7c0e30cee53dc038c Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 30 Nov 2021 12:50:02 +0200 Subject: [PATCH 281/303] improvements (remove security if a new device profile has been set) --- .../lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index dc96b1a9d2..3a24a19d9b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -392,12 +392,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { + public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional newDeviceProfileOpt) { try { LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId()); if (client != null) { - this.securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); - this.onDeviceUpdate(client, device, deviceProfileOpt); + if (newDeviceProfileOpt.isPresent()) { + this.securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); + } + this.onDeviceUpdate(client, device, newDeviceProfileOpt); } } catch (Exception e) { log.warn("[{}] failed to update device: {}", device.getId(), device); From 0909603ae5c03d1f33eba6b5a7762105586cb34f Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 30 Nov 2021 14:39:24 +0200 Subject: [PATCH 282/303] added description for the network config --- application/src/main/resources/thingsboard.yml | 6 +++--- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 1273555176..c5f4eaf6a0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -819,9 +819,9 @@ transport: log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" - network_config: - - key: "PROTOCOL_STAGE_THREAD_COUNT" - value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:12}" + network_config: # In this section you can specify custom parameters for LwM2M network configuration and expose the env variables to configure outside +# - key: "PROTOCOL_STAGE_THREAD_COUNT" +# value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:4}" snmp: enabled: "${SNMP_ENABLED:true}" response_processing: diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 34c08029b0..fd7c905263 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -204,9 +204,9 @@ transport: paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" - network_config: - - key: "PROTOCOL_STAGE_THREAD_COUNT" - value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:12}" + network_config: # In this section you can specify custom parameters for LwM2M network configuration and expose the env variables to configure outside + # - key: "PROTOCOL_STAGE_THREAD_COUNT" + # value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:4}" stats: enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" From 2a3f17a00fd2f0b22d7023a1dbb0539a3c1a3b77 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 30 Nov 2021 17:35:49 +0200 Subject: [PATCH 283/303] Remove redundant parameter --- application/src/main/resources/thingsboard.yml | 1 - .../transport/lwm2m/config/LwM2MTransportServerConfig.java | 4 ---- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 1 - 3 files changed, 6 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 85394e67a8..69bfd06bc8 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -816,7 +816,6 @@ transport: downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}" ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" - log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" snmp: diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index f444b74c2b..5c0c744eaf 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -90,10 +90,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Value("${transport.lwm2m.server.security.bind_port:}") private Integer securePort; - @Getter - @Value("${transport.lwm2m.log_max_length:}") - private int logMaxLength; - @Getter @Value("${transport.lwm2m.psm_activity_timer:10000}") private long psmActivityTimer; diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 8864b99e8c..52abec8f2d 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -199,7 +199,6 @@ transport: downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}" ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" - log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}" paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" # Use redis for Security and Registration stores From a760aa6ac28f913f9206a71a16f2adad97965a3d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 1 Dec 2021 14:41:02 +0200 Subject: [PATCH 284/303] Input and Output rule nodes and message routing --- .../actors/ruleChain/DefaultTbContext.java | 20 ++++ .../actors/ruleChain/RuleChainActor.java | 6 ++ .../RuleChainActorMessageProcessor.java | 71 +++++++++----- .../actors/ruleChain/RuleChainInputMsg.java | 41 ++++++++ .../actors/ruleChain/RuleChainOutputMsg.java | 49 ++++++++++ .../ruleChain/RuleChainToRuleChainMsg.java | 18 +--- .../ruleChain/TbToRuleChainActorMsg.java | 50 ++++++++++ .../server/actors/tenant/TenantActor.java | 4 + .../server/common/msg/MsgType.java | 10 ++ .../thingsboard/server/common/msg/TbMsg.java | 74 ++++++++++----- .../server/common/msg/TbMsgProcessingCtx.java | 94 +++++++++++++++++++ .../common/msg/TbMsgProcessingStackItem.java | 38 ++++++++ .../common/msg/queue/RuleNodeException.java | 3 +- common/message/src/main/proto/tbmsg.proto | 19 +++- .../rule/engine/api/TbContext.java | 19 ++++ .../engine/flow/TbRuleChainInputNode.java | 65 +++++++++++++ .../TbRuleChainInputNodeConfiguration.java | 32 +++++++ .../engine/flow/TbRuleChainOutputNode.java | 58 ++++++++++++ .../TbRuleChainOutputNodeConfiguration.java | 35 +++++++ 19 files changed, 642 insertions(+), 64 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainInputMsg.java create mode 100644 application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainOutputMsg.java create mode 100644 application/src/main/java/org/thingsboard/server/actors/ruleChain/TbToRuleChainActorMsg.java create mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java create mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeConfiguration.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index e3896b87a9..38d6f4bccb 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -56,6 +56,7 @@ import org.thingsboard.server.common.data.rule.RuleNodeState; import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.TbMsgProcessingStackItem; import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -134,6 +135,25 @@ class DefaultTbContext implements TbContext { scheduleMsgWithDelay(new RuleNodeToSelfMsg(this, msg), delayMs, nodeCtx.getSelfActor()); } + @Override + public void input(TbMsg msg, RuleChainId ruleChainId) { + msg.pushToStack(nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); + nodeCtx.getChainActor().tell(new RuleChainInputMsg(ruleChainId, msg)); + } + + @Override + public void output(TbMsg msg, String relationType) { + TbMsgProcessingStackItem item = msg.popFormStack(); + if (item == null) { + ack(msg); + } else { + if (nodeCtx.getSelf().isDebugMode()) { + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType); + } + nodeCtx.getChainActor().tell(new RuleChainOutputMsg(item.getRuleChainId(), item.getRuleNodeId(), relationType, msg)); + } + } + @Override public void enqueue(TbMsg tbMsg, Runnable onSuccess, Consumer onFailure) { TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator()); diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java index c019e64e1f..48785bda75 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java @@ -60,6 +60,12 @@ public class RuleChainActor extends ComponentActor { + private static final String NA_RELATION_TYPE = ""; private final TbActorRef parent; private final TbActorRef self; private final Map nodeActors; @@ -201,33 +202,58 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor 0) { @@ -167,7 +173,7 @@ public final class TbMsg implements Serializable { this.data = data; this.ruleChainId = ruleChainId; this.ruleNodeId = ruleNodeId; - this.ruleNodeExecCounter = new AtomicInteger(ruleNodeExecCounter); + this.ctx = ctx != null ? ctx : new TbMsgProcessingCtx(); if (callback != null) { this.callback = callback; } else { @@ -209,7 +215,8 @@ public final class TbMsg implements Serializable { builder.setDataType(msg.getDataType().ordinal()); builder.setData(msg.getData()); - builder.setRuleNodeExecCounter(msg.ruleNodeExecCounter.get()); + + builder.setCtx(msg.ctx.toProto()); return builder.build().toByteArray(); } @@ -231,8 +238,17 @@ public final class TbMsg implements Serializable { ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB())); } + TbMsgProcessingCtx ctx; + if (proto.hasCtx()) { + ctx = TbMsgProcessingCtx.fromProto(proto.getCtx()); + } else { + // Backward compatibility with unprocessed messages fetched from queue after update. + ctx = new TbMsgProcessingCtx(proto.getRuleNodeExecCounter()); + } + TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; - return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, proto.getRuleNodeExecCounter(), callback); + return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, + metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, ctx, callback); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Could not parse protobuf for TbMsg", e); } @@ -243,11 +259,13 @@ public final class TbMsg implements Serializable { } public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, null, this.ruleNodeExecCounter.get(), callback); + return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, + this.metaData, this.dataType, this.data, ruleChainId, null, this.ctx, callback); } public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ruleNodeExecCounter.get(), callback); + return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, + this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx, callback); } public TbMsgCallback getCallback() { @@ -262,4 +280,12 @@ public final class TbMsg implements Serializable { public String getQueueName() { return queueName != null ? queueName : ServiceQueue.MAIN; } + + public void pushToStack(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + ctx.push(ruleChainId, ruleNodeId); + } + + public TbMsgProcessingStackItem popFormStack() { + return ctx.pop(); + } } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java new file mode 100644 index 0000000000..9f3b78fffa --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -0,0 +1,94 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.msg; + +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.msg.gen.MsgProtos; + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by ashvayka on 13.01.18. + */ +public final class TbMsgProcessingCtx implements Serializable { + + private final AtomicInteger ruleNodeExecCounter; + private volatile LinkedList stack; + + public TbMsgProcessingCtx() { + this(0); + } + + public TbMsgProcessingCtx(int ruleNodeExecCounter) { + this(ruleNodeExecCounter, null); + } + + protected TbMsgProcessingCtx(int ruleNodeExecCounter, LinkedList stack) { + this.ruleNodeExecCounter = new AtomicInteger(ruleNodeExecCounter); + this.stack = stack; + } + + public int getAndIncrementRuleNodeCounter() { + return ruleNodeExecCounter.getAndIncrement(); + } + + public TbMsgProcessingCtx copy() { + return new TbMsgProcessingCtx(ruleNodeExecCounter.get()); + } + + public void push(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + if (stack == null) { + stack = new LinkedList<>(); + } + stack.add(new TbMsgProcessingStackItem(ruleChainId, ruleNodeId)); + } + + public TbMsgProcessingStackItem pop() { + return !stack.isEmpty() ? stack.removeLast() : null; + } + + public static TbMsgProcessingCtx fromProto(MsgProtos.TbMsgProcessingCtxProto ctx) { + int ruleNodeExecCounter = ctx.getRuleNodeExecCounter(); + if (ctx.getStackCount() > 0) { + LinkedList stack = new LinkedList<>(); + for (MsgProtos.TbMsgProcessingStackItemProto item : ctx.getStackList()) { + stack.add(new TbMsgProcessingStackItem( + new RuleChainId(new UUID(item.getRuleChainIdMSB(), item.getRuleChainIdLSB())), + new RuleNodeId(new UUID(item.getRuleNodeIdMSB(), item.getRuleNodeIdLSB())) + )); + } + return new TbMsgProcessingCtx(ruleNodeExecCounter, stack); + } else { + return new TbMsgProcessingCtx(ruleNodeExecCounter); + } + } + + public MsgProtos.TbMsgProcessingCtxProto toProto() { + var ctxBuilder = MsgProtos.TbMsgProcessingCtxProto.newBuilder(); + ctxBuilder.setRuleNodeExecCounter(ruleNodeExecCounter.get()); + if (stack != null) { + for (TbMsgProcessingStackItem item : stack) { + ctxBuilder.addStack(item.toProto()); + } + } + return ctxBuilder.build(); + } +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java new file mode 100644 index 0000000000..ff765594fe --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.msg; + +import lombok.Data; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.msg.gen.MsgProtos; + +@Data +public class TbMsgProcessingStackItem { + + private final RuleChainId ruleChainId; + private final RuleNodeId ruleNodeId; + + MsgProtos.TbMsgProcessingStackItemProto toProto() { + return MsgProtos.TbMsgProcessingStackItemProto.newBuilder() + .setRuleChainIdMSB(ruleChainId.getId().getMostSignificantBits()) + .setRuleChainIdLSB(ruleChainId.getId().getLeastSignificantBits()) + .setRuleNodeIdMSB(ruleNodeId.getId().getMostSignificantBits()) + .setRuleNodeIdLSB(ruleNodeId.getId().getLeastSignificantBits()) + .build(); + } + +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleNodeException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleNodeException.java index cd073f3a6e..44e30487d6 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleNodeException.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleNodeException.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.rule.RuleNode; public class RuleNodeException extends RuleEngineException { private static final long serialVersionUID = -1776681087370749776L; + public static final String UNKNOWN = "Unknown"; @Getter private final String ruleChainName; @@ -45,7 +46,7 @@ public class RuleNodeException extends RuleEngineException { this.ruleChainId = ruleNode.getRuleChainId(); this.ruleNodeId = ruleNode.getId(); } else { - ruleNodeName = "Unknown"; + ruleNodeName = UNKNOWN; ruleChainId = new RuleChainId(RuleChainId.NULL_UUID); ruleNodeId = new RuleNodeId(RuleNodeId.NULL_UUID); } diff --git a/common/message/src/main/proto/tbmsg.proto b/common/message/src/main/proto/tbmsg.proto index 75f5051fbf..4d7682634b 100644 --- a/common/message/src/main/proto/tbmsg.proto +++ b/common/message/src/main/proto/tbmsg.proto @@ -19,10 +19,24 @@ package msgqueue; option java_package = "org.thingsboard.server.common.msg.gen"; option java_outer_classname = "MsgProtos"; +// Stores message metadata as map of strings message TbMsgMetaDataProto { map data = 1; } +// Stores stack of nested (caller) rule chains +message TbMsgProcessingStackItemProto { + int64 ruleChainIdMSB = 1; + int64 ruleChainIdLSB = 2; + int64 ruleNodeIdMSB = 3; + int64 ruleNodeIdLSB = 4; +} + +message TbMsgProcessingCtxProto { + int32 ruleNodeExecCounter = 1; + repeated TbMsgProcessingStackItemProto stack = 2; +} + message TbMsgProto { string id = 1; string type = 2; @@ -39,14 +53,17 @@ message TbMsgProto { TbMsgMetaDataProto metaData = 11; - //Transaction Data (12) was removed in 2.5 + // Transaction Data (12) was removed in 2.5 int32 dataType = 13; string data = 14; int64 ts = 15; + // Will be removed in 3.4. Moved to processing context int32 ruleNodeExecCounter = 16; int64 customerIdMSB = 17; int64 customerIdLSB = 18; + + TbMsgProcessingCtxProto ctx = 19; } \ No newline at end of file diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index 239c86ed57..206256e190 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -121,6 +122,24 @@ public interface TbContext { */ void enqueue(TbMsg msg, Runnable onSuccess, Consumer onFailure); + /** + * Sends message to the nested rule chain. + * Fails processing of the message if the nested rule chain is not found. + * + * @param msg - the message + * @param ruleChainId - the id of a nested rule chain + */ + void input(TbMsg msg, RuleChainId ruleChainId); + + /** + * Sends message to the caller rule chain. + * Acknowledge the message if no caller rule chain is present in processing stack + * + * @param msg - the message + * @param relationType - the relation type that will be used to route messages in the caller rule chain + */ + void output(TbMsg msg, String relationType); + /** * Puts new message to custom queue for processing * diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java new file mode 100644 index 0000000000..c30dac406c --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java @@ -0,0 +1,65 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.flow; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; + +import java.util.UUID; + +@Slf4j +@RuleNode( + type = ComponentType.ACTION, + name = "rule chain input", + configClazz = TbRuleChainInputNodeConfiguration.class, + nodeDescription = "transfers the message to another rule chain", + nodeDetails = "Allows to nest the rule chain similar to single rule node. " + + "The incoming message is forwarded to the input node of the specified target rule chain. " + + "The target rule chain may produce multiple labeled outputs. " + + "You may use the outputs to forward the results of processing to other rule nodes.", + customRelations = true +) +public class TbRuleChainInputNode implements TbNode { + + private TbRuleChainInputNodeConfiguration config; + private RuleChainId ruleChainId; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbRuleChainInputNodeConfiguration.class); + this.ruleChainId = new RuleChainId(UUID.fromString(config.getRuleChainId())); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) { + ctx.input(msg, ruleChainId); + } + + @Override + public void destroy() { + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeConfiguration.java new file mode 100644 index 0000000000..b990411216 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeConfiguration.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.flow; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.server.common.data.id.RuleChainId; + +@Data +public class TbRuleChainInputNodeConfiguration implements NodeConfiguration { + + private String ruleChainId; + + @Override + public TbRuleChainInputNodeConfiguration defaultConfiguration() { + return new TbRuleChainInputNodeConfiguration(); + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java new file mode 100644 index 0000000000..b09f1bbca5 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java @@ -0,0 +1,58 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.flow; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; + +@Slf4j +@RuleNode( + type = ComponentType.ACTION, + name = "rule chain output", + configClazz = TbRuleChainOutputNodeConfiguration.class, + nodeDescription = "transfers the message to the caller rule chain", + nodeDetails = "Produces output of the rule chain processing. " + + "The output is forwarded to the caller rule chain, as an output of the corresponding \"input\" rule node. " + + "The rule node configuration contains the \"label\" parameter. " + + "This parameter corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ", + outEnabled = false +) +public class TbRuleChainOutputNode implements TbNode { + + private TbRuleChainOutputNodeConfiguration config; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbRuleChainOutputNodeConfiguration.class); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) { + ctx.output(msg, config.getLabel()); + } + + @Override + public void destroy() { + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java new file mode 100644 index 0000000000..8d220530c3 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.flow; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.server.common.data.DataConstants; + +@Data +public class TbRuleChainOutputNodeConfiguration implements NodeConfiguration { + + private String label; + + @Override + public TbRuleChainOutputNodeConfiguration defaultConfiguration() { + var result = new TbRuleChainOutputNodeConfiguration(); + result.setLabel(TbRelationTypes.SUCCESS); + return result; + } + +} From c3fa9b9f43403c3da00bd3da26f0e9303cdc9b94 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 2 Dec 2021 19:13:18 +0200 Subject: [PATCH 285/303] Nested rule chains --- .../controller/RuleChainController.java | 69 +++++++- .../rule/DefaultTbRuleChainService.java | 157 ++++++++++++++++++ .../service/rule/TbRuleChainService.java | 19 +++ .../server/dao/rule/RuleChainService.java | 5 +- .../common/data/rule/RuleChainMetaData.java | 1 + .../data/rule/RuleChainOutputLabelsUsage.java | 45 +++++ .../data/rule/RuleChainUpdateResult.java | 44 +++++ .../data/rule/RuleNodeUpdateResult.java | 32 ++++ .../server/common/msg/TbMsgProcessingCtx.java | 13 +- .../common/msg/TbMsgProcessingStackItem.java | 9 + .../server/dao/rule/BaseRuleChainService.java | 28 +++- .../server/dao/rule/RuleChainDao.java | 3 + .../server/dao/rule/RuleNodeDao.java | 4 + .../server/dao/sql/rule/JpaRuleChainDao.java | 7 + .../server/dao/sql/rule/JpaRuleNodeDao.java | 9 +- .../dao/sql/rule/RuleNodeRepository.java | 10 ++ .../dao/service/BaseRuleChainServiceTest.java | 4 +- 17 files changed, 439 insertions(+), 20 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainUpdateResult.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 2a8dcc3593..8345a8beef 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -28,7 +28,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -37,12 +36,16 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.ScriptEngine; +import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; +import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.tenant.DebugTbRateLimits; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Event; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -60,14 +63,18 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainImportResult; import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.event.EventService; +import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.install.InstallScripts; +import org.thingsboard.server.service.rule.TbRuleChainService; import org.thingsboard.server.service.script.JsInvokeService; import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; import org.thingsboard.server.service.security.permission.Operation; @@ -77,6 +84,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -137,6 +145,9 @@ public class RuleChainController extends BaseController { + MARKDOWN_CODE_BLOCK_END + "\n\n Expected result JSON contains \"output\" and \"error\"."; + @Autowired + protected TbRuleChainService tbRuleChainService; + @Autowired private InstallScripts installScripts; @@ -169,6 +180,44 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Get Rule Chain output labels (getRuleChainOutputLabels)", + notes = "Fetch the unique labels for the \"output\" Rule Nodes that belong to the Rule Chain based on the provided Rule Chain Id. " + + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/ruleChain/{ruleChainId}/output/labels", method = RequestMethod.GET) + @ResponseBody + public Set getRuleChainOutputLabels( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + checkParameter(RULE_CHAIN_ID, strRuleChainId); + try { + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); + checkRuleChain(ruleChainId, Operation.READ); + return tbRuleChainService.getRuleChainOutputLabels(getTenantId(), ruleChainId); + } catch (Exception e) { + throw handleException(e); + } + } + + @ApiOperation(value = "Get output labels usage (getRuleChainOutputLabelsUsage)", + notes = "Fetch the list of rule chains and the relation types (labels) they use to process output of the current rule chain based on the provided Rule Chain Id. " + + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/ruleChain/{ruleChainId}/output/labels/usage", method = RequestMethod.GET) + @ResponseBody + public List getRuleChainOutputLabelsUsage( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + checkParameter(RULE_CHAIN_ID, strRuleChainId); + try { + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); + checkRuleChain(ruleChainId, Operation.READ); + return tbRuleChainService.getOutputLabelUsage(getCurrentUser().getTenantId(), ruleChainId); + } catch (Exception e) { + throw handleException(e); + } + } + @ApiOperation(value = "Get Rule Chain (getRuleChainById)", notes = "Fetch the Rule Chain Metadata object based on the provided Rule Chain Id. " + RULE_CHAIN_METADATA_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @@ -310,7 +359,11 @@ public class RuleChainController extends BaseController { @ResponseBody public RuleChainMetaData saveRuleChainMetaData( @ApiParam(value = "A JSON value representing the rule chain metadata.") - @RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException { + @RequestBody RuleChainMetaData ruleChainMetaData, + @ApiParam(value = "Update related rule nodes.") + //TODO: change default value to "false" before merge + @RequestParam(value = "updateRelated", required = false, defaultValue = "true") boolean updateRelated + ) throws ThingsboardException { try { TenantId tenantId = getTenantId(); if (debugPerTenantEnabled) { @@ -322,7 +375,13 @@ public class RuleChainController extends BaseController { } RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE); - checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData) ? true : null); + RuleChainUpdateResult result = ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData); + checkNotNull(result.isSuccess() ? true : null); + + if (updateRelated && result.isSuccess()) { + tbRuleChainService.updateRelatedRuleChains(tenantId, ruleChainMetaData.getRuleChainId(), result); + } + RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId())); if (RuleChainType.CORE.equals(ruleChain.getType())) { @@ -681,7 +740,7 @@ public class RuleChainController extends BaseController { } @ApiOperation(value = "Get Edge Rule Chains (getEdgeRuleChains)", - notes = "Returns a page of Rule Chains assigned to the specified edge. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) + notes = "Returns a page of Rule Chains assigned to the specified edge. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java new file mode 100644 index 0000000000..a76b448611 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -0,0 +1,157 @@ +package org.thingsboard.server.service.rule; + +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; +import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; +import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; +import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; +import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.permission.Operation; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +@TbCoreComponent +@Slf4j +public class DefaultTbRuleChainService implements TbRuleChainService { + + private final RuleChainService ruleChainService; + + @Override + public Set getRuleChainOutputLabels(TenantId tenantId, RuleChainId ruleChainId) { + RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId, ruleChainId); + Set outputLabels = new TreeSet<>(); + for (RuleNode ruleNode : metaData.getNodes()) { + if (isOutputRuleNode(ruleNode)) { + try { + var configuration = JacksonUtil.treeToValue(ruleNode.getConfiguration(), TbRuleChainOutputNodeConfiguration.class); + if (StringUtils.isNotEmpty(configuration.getLabel())) { + outputLabels.add(configuration.getLabel()); + } + } catch (Exception e) { + log.warn("[{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, e); + } + } + } + return outputLabels; + } + + @Override + public List getOutputLabelUsage(TenantId tenantId, RuleChainId ruleChainId) { + List ruleNodes = ruleChainService.findRuleNodesByTenantIdAndType(tenantId, TbRuleChainInputNode.class.getName(), ruleChainId.getId().toString()); + Map ruleChainNamesCache = new HashMap<>(); + // Additional filter, "just in case" the structure of the JSON configuration will change. + var filteredRuleNodes = ruleNodes.stream().filter(node -> { + try { + TbRuleChainInputNodeConfiguration configuration = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainInputNodeConfiguration.class); + return ruleChainId.getId().toString().equals(configuration.getRuleChainId()); + } catch (Exception e) { + log.warn("[{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, e); + return false; + } + }).collect(Collectors.toList()); + + + return filteredRuleNodes.stream() + .map(ruleNode -> { + RuleChainOutputLabelsUsage usage = new RuleChainOutputLabelsUsage(); + usage.setRuleNodeId(ruleNode.getId()); + usage.setRuleNodeName(ruleNode.getName()); + usage.setRuleChainId(ruleNode.getRuleChainId()); + List relations = ruleChainService.getRuleNodeRelations(tenantId, ruleNode.getId()); + if (relations != null && !relations.isEmpty()) { + usage.setLabels(relations.stream().map(EntityRelation::getType).collect(Collectors.toSet())); + } + return usage; + }) + .filter(usage -> usage.getLabels() != null) + .peek(usage -> { + String ruleChainName = ruleChainNamesCache.computeIfAbsent(usage.getRuleChainId(), + id -> ruleChainService.findRuleChainById(tenantId, id).getName()); + usage.setRuleChainName(ruleChainName); + }) + .sorted(Comparator + .comparing(RuleChainOutputLabelsUsage::getRuleChainName) + .thenComparing(RuleChainOutputLabelsUsage::getRuleNodeName)) + .collect(Collectors.toList()); + } + + @Override + public void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result) { + log.debug("[{}][{}] Going to update links in related rule chains", tenantId, ruleChainId); + if (result.getUpdatedRuleNodes() == null || result.getUpdatedRuleNodes().isEmpty()) { + return; + } + + Set oldLabels = new HashSet<>(); + Set newLabels = new HashSet<>(); + Set confusedLabels = new HashSet<>(); + Map updatedLabels = new HashMap<>(); + for (RuleNodeUpdateResult update : result.getUpdatedRuleNodes()) { + var node = update.getNewRuleNode(); + if (isOutputRuleNode(node)) { + try { + TbRuleChainOutputNodeConfiguration oldConf = JacksonUtil.treeToValue(update.getOldConfiguration(), TbRuleChainOutputNodeConfiguration.class); + TbRuleChainOutputNodeConfiguration newConf = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainOutputNodeConfiguration.class); + oldLabels.add(oldConf.getLabel()); + newLabels.add(newConf.getLabel()); + if (!oldConf.getLabel().equals(newConf.getLabel())) { + String oldLabel = oldConf.getLabel(); + String newLabel = newConf.getLabel(); + if (updatedLabels.containsKey(oldLabel)) { + confusedLabels.add(oldLabel); + } else { + updatedLabels.put(oldLabel, newLabel); + } + + } + } catch (Exception e) { + log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, node.getId(), e); + } + } + } + // Remove all labels that are renamed to two or more different labels, since we don't which new label to use; + confusedLabels.forEach(updatedLabels::remove); + // Remove all labels that are renamed to different new labels; + newLabels.forEach(updatedLabels::remove); + if (!oldLabels.equals(newLabels)) { + for (upda) + } + } + + private boolean isOutputRuleNode(RuleNode ruleNode) { + return isRuleNode(ruleNode, TbRuleChainOutputNode.class); + } + + private boolean isInputRuleNode(RuleNode ruleNode) { + return isRuleNode(ruleNode, TbRuleChainInputNode.class); + } + + private boolean isRuleNode(RuleNode ruleNode, Class clazz) { + return ruleNode.getType().equals(clazz.getName()); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java new file mode 100644 index 0000000000..06f8c73dad --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java @@ -0,0 +1,19 @@ +package org.thingsboard.server.service.rule; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; + +import java.util.List; +import java.util.Set; + +public interface TbRuleChainService { + + Set getRuleChainOutputLabels(TenantId tenantId, RuleChainId ruleChainId); + + List getOutputLabelUsage(TenantId tenantId, RuleChainId ruleChainId); + + void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result); +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index e089d7bf47..f46393b5d1 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -28,7 +28,9 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainImportResult; import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; import java.util.List; @@ -42,7 +44,7 @@ public interface RuleChainService { boolean setRootRuleChain(TenantId tenantId, RuleChainId ruleChainId); - boolean saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData); + RuleChainUpdateResult saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData); RuleChainMetaData loadRuleChainMetaData(TenantId tenantId, RuleChainId ruleChainId); @@ -88,4 +90,5 @@ public interface RuleChainService { PageData findAutoAssignToEdgeRuleChainsByTenantId(TenantId tenantId, PageLink pageLink); + List findRuleNodesByTenantIdAndType(TenantId tenantId, String name, String toString); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java index 00b64ba9a9..2193e86f66 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; import javax.validation.Valid; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Created by igor on 3/13/18. diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java new file mode 100644 index 0000000000..0283dbf517 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.rule; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; + +import java.util.Set; + +@ApiModel +@Data +@Slf4j +public class RuleChainOutputLabelsUsage { + + @ApiModelProperty(position = 1, required = true, value = "Rule Chain Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private RuleChainId ruleChainId; + @ApiModelProperty(position = 2, required = true, value = "Rule Node Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private RuleNodeId ruleNodeId; + + @ApiModelProperty(position = 3, required = true, value = "Rule Chain Name", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private String ruleChainName; + @ApiModelProperty(position = 4, required = true, value = "Rule Node Name", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private String ruleNodeName; + @ApiModelProperty(position = 5, required = true, value = "Output labels", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private Set labels; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainUpdateResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainUpdateResult.java new file mode 100644 index 0000000000..76e6ce9870 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainUpdateResult.java @@ -0,0 +1,44 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.rule; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.thingsboard.server.common.data.id.RuleNodeId; + +import java.util.List; +import java.util.Map; + +/** + * Created by igor on 3/13/18. + */ +@Data +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class RuleChainUpdateResult { + + private final boolean success; + private final List updatedRuleNodes; + + public static RuleChainUpdateResult failed(){ + return new RuleChainUpdateResult(false, null); + } + + public static RuleChainUpdateResult successful(List updatedRuleNodes){ + return new RuleChainUpdateResult(true, updatedRuleNodes); + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java new file mode 100644 index 0000000000..a279533138 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.rule; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; +import org.thingsboard.server.common.data.id.RuleNodeId; + +import java.util.Map; + +/** + * Created by igor on 3/13/18. + */ +@Data +public class RuleNodeUpdateResult { + + private final JsonNode oldConfiguration; + private final RuleNode newRuleNode; +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java index 9f3b78fffa..7d65108b1f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -51,7 +51,11 @@ public final class TbMsgProcessingCtx implements Serializable { } public TbMsgProcessingCtx copy() { - return new TbMsgProcessingCtx(ruleNodeExecCounter.get()); + if (stack == null || stack.isEmpty()) { + return new TbMsgProcessingCtx(ruleNodeExecCounter.get()); + } else { + return new TbMsgProcessingCtx(ruleNodeExecCounter.get(), new LinkedList<>(stack)); + } } public void push(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { @@ -70,10 +74,7 @@ public final class TbMsgProcessingCtx implements Serializable { if (ctx.getStackCount() > 0) { LinkedList stack = new LinkedList<>(); for (MsgProtos.TbMsgProcessingStackItemProto item : ctx.getStackList()) { - stack.add(new TbMsgProcessingStackItem( - new RuleChainId(new UUID(item.getRuleChainIdMSB(), item.getRuleChainIdLSB())), - new RuleNodeId(new UUID(item.getRuleNodeIdMSB(), item.getRuleNodeIdLSB())) - )); + stack.add(TbMsgProcessingStackItem.fromProto(item)); } return new TbMsgProcessingCtx(ruleNodeExecCounter, stack); } else { diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java index ff765594fe..6490ddf547 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java @@ -20,6 +20,8 @@ import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.msg.gen.MsgProtos; +import java.util.UUID; + @Data public class TbMsgProcessingStackItem { @@ -35,4 +37,11 @@ public class TbMsgProcessingStackItem { .build(); } + static TbMsgProcessingStackItem fromProto(MsgProtos.TbMsgProcessingStackItemProto item){ + return new TbMsgProcessingStackItem( + new RuleChainId(new UUID(item.getRuleChainIdMSB(), item.getRuleChainIdLSB())), + new RuleNodeId(new UUID(item.getRuleNodeIdMSB(), item.getRuleNodeIdLSB())) + ); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 32dbe39502..a2378225e4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -47,8 +47,11 @@ import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainImportResult; import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -72,6 +75,7 @@ import java.util.stream.Collectors; import static org.thingsboard.server.common.data.DataConstants.TENANT; import static org.thingsboard.server.dao.service.Validator.validateId; +import static org.thingsboard.server.dao.service.Validator.validateString; /** * Created by igor on 3/12/18. @@ -130,13 +134,14 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Override @Transactional - public boolean saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData) { + public RuleChainUpdateResult saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData) { Validator.validateId(ruleChainMetaData.getRuleChainId(), "Incorrect rule chain id."); RuleChain ruleChain = findRuleChainById(tenantId, ruleChainMetaData.getRuleChainId()); if (ruleChain == null) { - return false; + return RuleChainUpdateResult.failed(); } ConstraintValidator.validateFields(ruleChainMetaData); + List updatedRuleNodes = new ArrayList<>(); if (CollectionUtils.isNotEmpty(ruleChainMetaData.getConnections())) { validateCircles(ruleChainMetaData.getConnections()); @@ -161,11 +166,15 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC for (RuleNode existingNode : existingRuleNodes) { deleteEntityRelations(tenantId, existingNode.getId()); Integer index = ruleNodeIndexMap.get(existingNode.getId()); + RuleNode newRuleNode = null; if (index != null) { - toAddOrUpdate.add(ruleChainMetaData.getNodes().get(index)); + newRuleNode = ruleChainMetaData.getNodes().get(index); + toAddOrUpdate.add(newRuleNode); } else { + updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), null)); toDelete.add(existingNode); } + updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), newRuleNode)); } if (nodes != null) { for (RuleNode node : toAddOrUpdate) { @@ -209,7 +218,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } } - return true; + return RuleChainUpdateResult.successful(updatedRuleNodes); } private void validateCircles(List connectionInfos) { @@ -652,6 +661,15 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return ruleChainDao.findAutoAssignToEdgeRuleChainsByTenantId(tenantId.getId(), pageLink); } + @Override + public List findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String search) { + log.trace("Executing findRuleNodes, tenantId [{}], type {}, search {}", tenantId, type, search); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateString(type, "Incorrect type of the rule node"); + validateString(search, "Incorrect search text"); + return ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId, type, search); + } + private void checkRuleNodesAndDelete(TenantId tenantId, RuleChainId ruleChainId) { try { ruleChainDao.removeById(tenantId, ruleChainId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index 03fd25e944..bf036a8105 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java @@ -19,11 +19,13 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.TenantEntityDao; import java.util.Collection; +import java.util.List; import java.util.UUID; /** @@ -79,4 +81,5 @@ public interface RuleChainDao extends Dao, TenantEntityDao { Collection findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name); + List getOutputLabelUsage(UUID id, UUID id1); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java index 46bfefc15e..4002867ba9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java @@ -15,12 +15,16 @@ */ package org.thingsboard.server.dao.rule; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.dao.Dao; +import java.util.List; + /** * Created by igor on 3/12/18. */ public interface RuleNodeDao extends Dao { + List findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String search); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 483ab39f06..b432b04f04 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RuleChainEntity; @@ -30,6 +31,7 @@ import org.thingsboard.server.dao.rule.RuleChainDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import java.util.Collection; +import java.util.List; import java.util.Objects; import java.util.UUID; @@ -103,6 +105,11 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao getOutputLabelUsage(UUID tenantId, UUID ruleChainId) { + return null; + } + @Override public Long countByTenantId(TenantId tenantId) { return ruleChainRepository.countByTenantId(tenantId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java index 362299f9b3..4b541f8df5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -19,11 +19,14 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RuleNodeEntity; import org.thingsboard.server.dao.rule.RuleNodeDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import java.util.List; import java.util.UUID; @Slf4j @@ -43,4 +46,8 @@ public class JpaRuleNodeDao extends JpaAbstractSearchTextDao findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String search) { + return DaoUtil.convertDataList(ruleNodeRepository.findRuleNodesByTenantIdAndType(tenantId.getId(), type, search)); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java index 09e4bb55ae..77bd5d4a38 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java @@ -15,11 +15,21 @@ */ package org.thingsboard.server.dao.sql.rule; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.thingsboard.server.dao.model.sql.RuleNodeEntity; +import java.util.List; import java.util.UUID; public interface RuleNodeRepository extends CrudRepository { + @Query("SELECT r FROM RuleNodeEntity r WHERE r.ruleChainId in " + + "(select id from RuleChainEntity rc WHERE rc.tenantId = :tenantId) " + + "AND r.type = :ruleType AND LOWER(r.configuration) LIKE LOWER(CONCAT('%', :searchText, '%')) ") + List findRuleNodesByTenantIdAndType(@Param("tenantId") UUID tenantId, + @Param("ruleType") String ruleType, + @Param("searchText") String searchText); + } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java index 109814d330..c1635a6281 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java @@ -293,7 +293,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { ruleNodes.set(name3Index, ruleNode4); - Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, savedRuleChainMetaData)); + Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, savedRuleChainMetaData).isSuccess()); RuleChainMetaData updatedRuleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, savedRuleChainMetaData.getRuleChainId()); Assert.assertEquals(3, updatedRuleChainMetaData.getNodes().size()); @@ -406,7 +406,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { ruleChainMetaData.addConnectionInfo(0,2,"fail"); ruleChainMetaData.addConnectionInfo(1,2,"success"); - Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData)); + Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData).isSuccess()); return ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId()); } From 9cf0ab69001f3a798c1a093513ebfccdf0a826b2 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 2 Dec 2021 20:00:24 +0200 Subject: [PATCH 286/303] Rename of the related rule chains when customer renames the output label --- .../controller/RuleChainController.java | 2 +- .../rule/DefaultTbRuleChainService.java | 49 +++++++++++++++++-- .../service/rule/TbRuleChainService.java | 15 ++++++ .../data/rule/RuleChainOutputLabelsUsage.java | 2 +- .../server/common/msg/TbMsgProcessingCtx.java | 2 +- .../server/dao/rule/BaseRuleChainService.java | 2 +- .../server/dao/sql/rule/JpaRuleNodeDao.java | 2 +- 7 files changed, 65 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 8345a8beef..9122990339 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index a76b448611..414abcb0ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2021 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.rule; import com.fasterxml.jackson.core.JsonProcessingException; @@ -11,6 +26,7 @@ import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rule.RuleChain; @@ -19,6 +35,7 @@ import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; +import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; @@ -40,6 +57,7 @@ import java.util.stream.Collectors; public class DefaultTbRuleChainService implements TbRuleChainService { private final RuleChainService ruleChainService; + private final RelationService relationService; @Override public Set getRuleChainOutputLabels(TenantId tenantId, RuleChainId ruleChainId) { @@ -122,8 +140,9 @@ public class DefaultTbRuleChainService implements TbRuleChainService { if (!oldConf.getLabel().equals(newConf.getLabel())) { String oldLabel = oldConf.getLabel(); String newLabel = newConf.getLabel(); - if (updatedLabels.containsKey(oldLabel)) { + if (updatedLabels.containsKey(oldLabel) && !updatedLabels.get(oldLabel).equals(newLabel)) { confusedLabels.add(oldLabel); + log.warn("[{}][{}] Can't automatically rename the label from [{}] to [{}] due to conflict [{}]", tenantId, ruleChainId, oldLabel, newLabel, updatedLabels.get(oldLabel)); } else { updatedLabels.put(oldLabel, newLabel); } @@ -134,12 +153,34 @@ public class DefaultTbRuleChainService implements TbRuleChainService { } } } - // Remove all labels that are renamed to two or more different labels, since we don't which new label to use; + // Remove all output labels that are renamed to two or more different labels, since we don't which new label to use; confusedLabels.forEach(updatedLabels::remove); - // Remove all labels that are renamed to different new labels; + // Remove all output labels that are renamed but still present in the rule chain; newLabels.forEach(updatedLabels::remove); if (!oldLabels.equals(newLabels)) { - for (upda) + updateRelatedRuleChains(tenantId, ruleChainId, updatedLabels); + } + } + + public void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, Map labelsMap) { + List usageList = getOutputLabelUsage(tenantId, ruleChainId); + for (RuleChainOutputLabelsUsage usage : usageList) { + labelsMap.forEach((oldLabel, newLabel) -> { + if (usage.getLabels().contains(oldLabel)) { + renameOutgoingLinks(tenantId, usage.getRuleNodeId(), oldLabel, newLabel); + } + }); + } + } + + private void renameOutgoingLinks(TenantId tenantId, RuleNodeId ruleNodeId, String oldLabel, String newLabel) { + List relations = ruleChainService.getRuleNodeRelations(tenantId, ruleNodeId); + for (EntityRelation relation : relations) { + if (relation.getType().equals(oldLabel)) { + relationService.deleteRelation(tenantId, relation); + relation.setType(newLabel); + relationService.saveRelation(tenantId, relation); + } } } diff --git a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java index 06f8c73dad..d08f234d8e 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2021 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.rule; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java index 0283dbf517..3e0bde1c94 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java index 7d65108b1f..47bcf683b0 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index a2378225e4..b747fd4851 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java index 4b541f8df5..2e7d796cb3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java @@ -5,7 +5,7 @@ * 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 + * 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, From bbd1d8ae8683890d8aa0ea1971e3d63668e2aefc Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 3 Dec 2021 11:57:31 +0200 Subject: [PATCH 287/303] Migration script --- .../install/ThingsboardInstallService.java | 3 + .../update/DefaultDataUpdateService.java | 84 +++++++++++++++++++ .../rule/DefaultTbRuleChainService.java | 2 +- .../server/dao/relation/RelationService.java | 6 ++ .../server/dao/rule/RuleChainService.java | 2 + .../dao/relation/BaseRelationService.java | 17 +++- .../server/dao/relation/RelationDao.java | 5 +- .../server/dao/rule/BaseRuleChainService.java | 6 ++ .../dao/sql/relation/JpaRelationDao.java | 9 +- .../dao/sql/relation/RelationRepository.java | 21 +++++ .../dao/sql/rule/RuleChainRepository.java | 5 ++ 11 files changed, 153 insertions(+), 7 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 ccdac8b363..702a73decc 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -210,6 +210,9 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 3.3.0 to 3.3.1 ..."); case "3.3.1": log.info("Upgrading ThingsBoard from version 3.3.1 to 3.3.2 ..."); + case "3.3.2": + log.info("Upgrading ThingsBoard from version 3.3.2 to 3.3.3 ..."); + dataUpdateService.updateData("3.3.2"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index de483dfda8..e244a0f0b0 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -25,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; import org.thingsboard.server.common.data.EntityView; @@ -34,6 +36,8 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; @@ -43,8 +47,11 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.query.DynamicValue; import org.thingsboard.server.common.data.query.FilterPredicateValue; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.alarm.AlarmDao; @@ -52,7 +59,9 @@ import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; +import org.thingsboard.server.dao.model.sql.RelationEntity; import org.thingsboard.server.dao.oauth2.OAuth2Service; +import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.sql.device.DeviceProfileRepository; import org.thingsboard.server.dao.tenant.TenantService; @@ -76,6 +85,9 @@ public class DefaultDataUpdateService implements DataUpdateService { @Autowired private TenantService tenantService; + @Autowired + private RelationService relationService; + @Autowired private RuleChainService ruleChainService; @@ -125,6 +137,10 @@ public class DefaultDataUpdateService implements DataUpdateService { deviceProfileEntityDynamicConditionsUpdater.updateEntities(null); updateOAuth2Params(); break; + case "3.3.2": + log.info("Updating data from version 3.3.2 to 3.3.3 ..."); + nestedRuleNodeUpdater.updateEntities(null); + break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } @@ -209,6 +225,74 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; + private final PaginatedUpdater nestedRuleNodeUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants nested rule chain updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } + + @Override + protected PageData findEntities(String region, PageLink pageLink) { + return tenantService.findTenants(pageLink); + } + + @Override + protected void updateEntity(Tenant tenant) { + try { + var tenantId = tenant.getId(); + var packSize = 1024; + boolean hasNext = true; + while (hasNext) { + List relations = relationService.findRuleNodeToRuleChainRelations(tenantId, RuleChainType.CORE, packSize); + hasNext = relations.size() == packSize; + for (EntityRelation relation : relations) { + + RuleNode sourceNode = ruleChainService.findRuleNodeById(tenantId, new RuleNodeId(relation.getFrom().getId())); + RuleChainId sourceRuleChainId = sourceNode.getRuleChainId(); + RuleChain targetRuleChain = ruleChainService.findRuleChainById(tenantId, new RuleChainId(relation.getTo().getId())); + RuleNode targetNode = new RuleNode(); + targetNode.setName(targetRuleChain.getName()); + targetNode.setRuleChainId(sourceRuleChainId); + targetNode.setType(TbRuleChainInputNode.class.getName()); + TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration(); + configuration.setRuleChainId(targetRuleChain.getId().toString()); + targetNode.setConfiguration(JacksonUtil.valueToTree(configuration)); + targetNode.setAdditionalInfo(relation.getAdditionalInfo()); + targetNode.setDebugMode(false); + targetNode = ruleChainService.saveRuleNode(tenantId, targetNode); + + EntityRelation sourceRuleChainToRuleNode = new EntityRelation(); + sourceRuleChainToRuleNode.setFrom(sourceRuleChainId); + sourceRuleChainToRuleNode.setTo(targetNode.getId()); + sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE); + sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN); + relationService.saveRelation(tenantId, sourceRuleChainToRuleNode); + + EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation(); + sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId()); + sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId()); + sourceRuleNodeToTargetRuleNode.setType(relation.getType()); + sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE); + sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo()); + relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode); + + //Delete old relation + relationService.deleteRelation(tenantId, relation); + } + } + } catch (Exception e) { + log.error("Unable to update Tenant", e); + } + } + }; + private final PaginatedUpdater tenantsDefaultEdgeRuleChainUpdater = new PaginatedUpdater<>() { diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index 414abcb0ef..e6d1ba1d8a 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -193,6 +193,6 @@ public class DefaultTbRuleChainService implements TbRuleChainService { } private boolean isRuleNode(RuleNode ruleNode, Class clazz) { - return ruleNode.getType().equals(clazz.getName()); + return ruleNode != null && ruleNode.getType().equals(clazz.getName()); } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java index c8f2a38005..87ac26b41e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java @@ -16,12 +16,16 @@ package org.thingsboard.server.dao.relation; import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChainType; import java.util.List; @@ -78,6 +82,8 @@ public interface RelationService { void removeRelations(TenantId tenantId, EntityId entityId); + List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit); + // TODO: This method may be useful for some validations in the future // ListenableFuture checkRecursiveRelation(EntityId from, EntityId to); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index f46393b5d1..48f16215bb 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -91,4 +91,6 @@ public interface RuleChainService { PageData findAutoAssignToEdgeRuleChainsByTenantId(TenantId tenantId, PageLink pageLink); List findRuleNodesByTenantIdAndType(TenantId tenantId, String name, String toString); + + RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 2be2331a99..1e1d0eee18 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -30,8 +30,11 @@ import org.springframework.cache.annotation.Caching; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; @@ -39,6 +42,7 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; +import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.ConstraintValidator; @@ -54,6 +58,7 @@ import java.util.concurrent.ExecutionException; import java.util.function.BiConsumer; import static org.thingsboard.server.common.data.CacheConstants.RELATIONS_CACHE; +import static org.thingsboard.server.dao.service.Validator.validateId; /** * Created by ashvayka on 28.04.17. @@ -194,11 +199,11 @@ public class BaseRelationService implements RelationService { outboundRelations.addAll(relationDao.findAllByFrom(tenantId, entityId, typeGroup)); } - for (EntityRelation relation : inboundRelations){ + for (EntityRelation relation : inboundRelations) { delete(tenantId, cache, relation, true); } - for (EntityRelation relation : outboundRelations){ + for (EntityRelation relation : outboundRelations) { delete(tenantId, cache, relation, false); } @@ -556,6 +561,14 @@ public class BaseRelationService implements RelationService { } } + @Override + public List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) { + log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}] and limit {}", + tenantId, limit); + validateId(tenantId, "Invalid tenant id: " + tenantId); + return relationDao.findRuleNodeToRuleChainRelations(tenantId, ruleChainType, limit); + } + protected void validate(EntityRelation relation) { if (relation == null) { throw new DataValidationException("Relation type should be specified!"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index d60f176832..efb516af3e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -16,13 +16,11 @@ package org.thingsboard.server.dao.relation; import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChainType; import java.util.List; @@ -63,4 +61,5 @@ public interface RelationDao { ListenableFuture deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity); + List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index b747fd4851..e1aaa31d3c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; @@ -670,6 +671,11 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId, type, search); } + @Override + public RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode) { + return ruleNodeDao.save(tenantId, ruleNode); + } + private void checkRuleNodesAndDelete(TenantId tenantId, RuleChainId ruleChainId) { try { ruleChainDao.removeById(tenantId, ruleChainId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 2eaa5c28a2..5291da6669 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EntityType; @@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RelationCompositeKey; import org.thingsboard.server.dao.model.sql.RelationEntity; @@ -196,11 +198,16 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple }); } + @Override + public List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) { + return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(tenantId.getId(), ruleChainType, PageRequest.of(0, limit))); + } + private Specification getEntityFieldsSpec(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType) { return (root, criteriaQuery, criteriaBuilder) -> { List predicates = new ArrayList<>(); if (from != null) { - Predicate fromIdPredicate = criteriaBuilder.equal(root.get("fromId"), from.getId()); + Predicate fromIdPredicate = criteriaBuilder.equal(root.get("fromId"), from.getId()); predicates.add(fromIdPredicate); Predicate fromEntityTypePredicate = criteriaBuilder.equal(root.get("fromType"), from.getEntityType().name()); predicates.add(fromEntityTypePredicate); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java index c5a1774ae6..28b125ac3c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java @@ -15,11 +15,20 @@ */ package org.thingsboard.server.dao.sql.relation; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.model.sql.RelationCompositeKey; import org.thingsboard.server.dao.model.sql.RelationEntity; +import org.thingsboard.server.dao.model.sql.RuleChainEntity; import java.util.List; import java.util.UUID; @@ -48,6 +57,17 @@ public interface RelationRepository List findAllByFromIdAndFromType(UUID fromId, String fromType); + @Query("SELECT r FROM RelationEntity r WHERE " + + "r.fromId in (SELECT id from RuleNodeEntity where ruleChainId in " + + "(SELECT id from RuleChainEntity where tenantId = :tenantId and type = :ruleChainType ))" + + "AND r.fromType = 'RULE_NODE' " + + "AND r.toType = 'RULE_CHAIN' " + + "AND r.relationTypeGroup = 'RULE_NODE'") + List findRuleNodeToRuleChainRelations( + @Param("tenantId") UUID tenantId, + @Param("ruleChainType") RuleChainType ruleChainType, + Pageable page); + @Transactional S save(S entity); @@ -56,4 +76,5 @@ public interface RelationRepository @Transactional void deleteByFromIdAndFromType(UUID fromId, String fromType); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java index 750b59e363..9b80dad34f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java @@ -20,7 +20,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.dao.model.sql.RelationEntity; import org.thingsboard.server.dao.model.sql.RuleChainEntity; import java.util.List; @@ -59,6 +63,7 @@ public interface RuleChainRepository extends PagingAndSortingRepository Date: Fri, 3 Dec 2021 14:04:31 +0200 Subject: [PATCH 288/303] logging improvements --- .../java/org/thingsboard/server/common/data/DeviceProfile.java | 2 ++ .../org/thingsboard/server/common/data/DeviceProfileInfo.java | 2 +- .../server/queue/usagestats/DefaultTbApiUsageClient.java | 2 +- .../server/transport/lwm2m/server/client/LwM2mClient.java | 2 ++ .../common/transport/service/DefaultTransportService.java | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 8a815547d6..cf916d9c74 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -21,6 +21,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.id.DashboardId; @@ -39,6 +40,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn @ApiModel @Data +@ToString(exclude = {"image", "profileDataBytes"}) @EqualsAndHashCode(callSuper = true) @Slf4j public class DeviceProfile extends SearchTextBased implements HasName, HasTenantId, HasOtaPackage { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java index a35b281a46..e9f4cc0100 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java @@ -29,7 +29,7 @@ import java.util.UUID; @Value @EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) +@ToString(callSuper = true, exclude = "image") public class DeviceProfileInfo extends EntityInfo { @ApiModelProperty(position = 3, value = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ") diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java index 370de259ef..92890da39f 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java @@ -125,7 +125,7 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient { })); if (!report.isEmpty()) { - log.info("Reporting API usage statistics for {} tenants and customers", report.size()); + log.debug("Reporting API usage statistics for {} tenants and customers", report.size()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 9534be8516..331881a327 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; @@ -64,6 +65,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.g @Slf4j @EqualsAndHashCode(of = {"endpoint"}) +@ToString(of = "endpoint") public class LwM2mClient implements Serializable { private static final long serialVersionUID = 8793482946289222623L; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index d83aa4d4d9..52e52c30f1 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -1184,7 +1184,7 @@ public class DefaultTransportService implements TransportService { @Scheduled(fixedDelayString = "${transport.stats.print-interval-ms:60000}") public void printStats() { - if (statsEnabled) { + if (statsEnabled && !statsMap.isEmpty()) { String values = statsMap.entrySet().stream() .map(kv -> kv.getKey() + " [" + kv.getValue() + "]").collect(Collectors.joining(", ")); log.info("Transport Stats: {}", values); From a69551f067d8ee857bd456805d294f3bc752da3e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 6 Dec 2021 12:54:48 +0200 Subject: [PATCH 289/303] Angular 12 migration --- .../static/rulenode/rulenode-core-config.js | 4190 +++++++++++- ui-ngx/.browserslistrc | 16 + ui-ngx/angular.json | 40 +- ui-ngx/extra-webpack.config.js | 14 +- ui-ngx/package.json | 112 +- ui-ngx/src/.browserslistrc | 10 - .../src/app/core/http/rule-chain.service.ts | 13 +- .../app/core/services/resources.service.ts | 119 +- .../app/modules/common/modules-map.models.ts | 19 + ui-ngx/src/app/modules/common/modules-map.ts | 579 +- .../states/states-controller.module.ts | 6 +- .../device/device-credentials.module.ts | 10 +- .../entity/entities-table.component.ts | 3 +- ...mplex-filter-predicate-dialog.component.ts | 20 +- .../complex-filter-predicate.component.ts | 16 +- .../filter/filter-component.models.ts | 29 + .../filter/filter-predicate-list.component.ts | 14 +- .../home/components/home-components.module.ts | 8 +- .../common/device-profile-common.module.ts | 4 +- .../lwm2m/lwm2m-profile-components.module.ts | 22 +- .../snmp-device-profile-transport.module.ts | 4 +- .../shared-home-components.module.ts | 4 + .../src/app/modules/home/components/tokens.ts | 27 + .../widget/dialog/custom-dialog.service.ts | 22 +- .../components/widget/lib/maps/leaflet-map.ts | 1 + .../lib/rpc/led-indicator.component.scss | 1 - .../lib/rpc/round-switch.component.scss | 1 - .../widget/widget-component.service.ts | 3 +- .../widget/widget-components.module.ts | 10 +- .../components/widget/widget.component.ts | 7 +- ui-ngx/src/app/modules/home/home.component.ts | 4 +- .../entity/entities-table-config.models.ts | 4 +- .../entity/entity-table-component.models.ts | 85 + .../rulechain/rulechain-routing.module.ts | 3 +- .../shared/components/cheatsheet.component.ts | 2 + .../components/fab-toolbar.component.scss | 13 +- .../shared/components/hotkeys.directive.ts | 3 +- .../json-form/react/json-form-react.tsx | 4 +- .../components/json-form/react/json-form.scss | 1 - .../react/styles/thingsboardTheme.ts | 2 +- .../shared/components/nav-tree.component.ts | 10 +- .../shared/components/popover.component.scss | 2 +- ui-ngx/src/app/shared/components/tokens.ts | 2 +- ui-ngx/src/app/shared/models/constants.ts | 3 +- ui-ngx/src/app/shared/shared.module.ts | 4 +- ui-ngx/src/scss/animations.scss | 1 - ui-ngx/src/scss/mixins.scss | 4 +- ui-ngx/src/theme.scss | 9 +- ui-ngx/src/tsconfig.app.json | 2 +- ui-ngx/tsconfig.json | 20 +- ui-ngx/yarn.lock | 5614 ++++------------- 51 files changed, 6361 insertions(+), 4755 deletions(-) create mode 100644 ui-ngx/.browserslistrc delete mode 100644 ui-ngx/src/.browserslistrc create mode 100644 ui-ngx/src/app/modules/common/modules-map.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/filter/filter-component.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/tokens.ts create mode 100644 ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts 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 3505c30a5a..8236c14be8 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,16 +1,4174 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@angular/core"),require("@angular/common"),require("@ngx-translate/core"),require("@shared/public-api"),require("@ngrx/store"),require("@angular/forms"),require("@home/components/public-api"),require("@core/public-api"),require("@angular/cdk/keycodes"),require("@angular/cdk/coercion"),require("@angular/material/chips"),require("@angular/material/autocomplete"),require("rxjs"),require("rxjs/operators"),require("@angular/platform-browser")):"function"==typeof define&&define.amd?define("rulenode-core-config",["exports","@angular/core","@angular/common","@ngx-translate/core","@shared/public-api","@ngrx/store","@angular/forms","@home/components/public-api","@core/public-api","@angular/cdk/keycodes","@angular/cdk/coercion","@angular/material/chips","@angular/material/autocomplete","rxjs","rxjs/operators","@angular/platform-browser"],t):t((e=e||self)["rulenode-core-config"]={},e.ng.core,e.ng.common,e["ngx-translate"],e.shared,e["ngrx-store"],e.ng.forms,e.publicApi$1,e.core,e.ng.cdk.keycodes,e.ng.cdk.coercion,e.ng.material.chips,e.ng.material.autocomplete,e.rxjs,e.rxjs.operators,e.ng.platformBrowser)}(this,(function(e,t,r,n,a,o,i,l,s,m,u,d,p,c,f,g){"use strict"; -/*! ***************************************************************************** - Copyright (c) Microsoft Corporation. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
        "}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
        tb.rulenode.notify-device-hint
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
        \n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
        \n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
        \n
        \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
        \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
        \n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
        tb.rulenode.create-entity-if-not-exists-hint
        \n
        \n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
        tb.rulenode.remove-current-relations-hint
        \n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
        tb.rulenode.change-originator-to-related-entity-hint
        \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
        \n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-period-in-seconds-patterns-hint
        \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
        \n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.delete-relation-hint
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
        \n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
        \n \n \n \n
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
        \n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
        \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
        \n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
        \n
        \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
        \n
        \n
        \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
        \n
        \n \n
        \n \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-type
        \n \n \n
        device.device-types
        \n \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
        \n \n {{ \'alias.last-level-relation\' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-filters
        \n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-message-types-found\n
        \n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
        \n
        \n
        \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
        \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
        {{ \'tb.rulenode.credentials-pem-hint\' | translate }}
        \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
        \n
        \n
        \n
        \n
        \n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
        \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
        \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
        \n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
        tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
        \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
        \n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
        \n \n tb.rulenode.client-id\n \n \n
        tb.rulenode.client-id-hint
        \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
        \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-webkit-fit-content;max-width:-moz-fit-content;max-width:fit-content}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
        \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
        \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n
        \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
        \n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
        \n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
        \n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
        \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
        \n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
        \n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
        \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
        \n
        \n
        \n
        \n
        \n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-webkit-fit-content;max-width:-moz-fit-content;max-width:fit-content}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
        \n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
        \n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
        \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
        tb.rulenode.check-all-keys-hint
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
        \n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
        tb.rulenode.check-relation-hint
        \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
        \n \n \n \n \n
        \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
        \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
        \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
        \n \n \n \n
        \n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
        \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-alarm-status-matching\n
        \n
        \n
        \n
        \n
        \n \n
        \n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
        \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-entity-details-matching\n
        \n
        \n
        \n
        \n
        \n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
        tb.rulenode.add-to-metadata-hint
        \n
        \n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
        \n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
        \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
        \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
        \n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.aggregationTypes=a.AggregationType,n.aggregations=Object.keys(a.AggregationType),n.aggregationTypesTranslations=a.aggregationTranslations,n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[i.Validators.required]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
        \n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
        \n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
        tb.rulenode.use-metadata-interval-patterns-hint
        \n
        \n
        \n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
        \n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
        \n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
        \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
        \n
        \n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
        \n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
        \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
        \n \n \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
        \n \n \n \n
        \n \n
        \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
        \n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
        \n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":"Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.Majority of the MQTT brokers will not allow multiple connections with the same client id. To connect to such brokers, your mqtt client id must be unique. When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-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","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); -//# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file +import * as i0 from '@angular/core'; +import { Component, Pipe, ViewChild, forwardRef, Input, NgModule } from '@angular/core'; +import * as i3$4 from '@shared/public-api'; +import { RuleNodeConfigurationComponent, AttributeScope, telemetryTypeTranslations, ServiceType, AlarmSeverity, alarmSeverityTranslations, EntitySearchDirection, entitySearchDirectionTranslations, EntityType, PageComponent, MessageType, messageTypeNames, SharedModule, AggregationType, aggregationTranslations, alarmStatusTranslations, AlarmStatus } from '@shared/public-api'; +import * as i1 from '@ngrx/store'; +import * as i2 from '@angular/forms'; +import { Validators, NgControl, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl } from '@angular/forms'; +import * as i3 from '@angular/material/form-field'; +import * as i3$1 from '@angular/material/checkbox'; +import * as i8 from '@angular/flex-layout/flex'; +import * as i4 from '@ngx-translate/core'; +import * as i11 from '@angular/material/input'; +import * as i10 from '@angular/common'; +import { CommonModule } from '@angular/common'; +import * as i1$1 from '@angular/platform-browser'; +import * as i4$1 from '@angular/material/select'; +import * as i5 from '@angular/material/core'; +import * as i4$2 from '@angular/material/expansion'; +import * as i7 from '@shared/components/button/toggle-password.component'; +import * as i8$1 from '@shared/components/file-input.component'; +import * as i3$2 from '@shared/components/queue/queue-type-list.component'; +import * as i3$3 from '@core/public-api'; +import { isDefinedAndNotNull } from '@core/public-api'; +import * as i5$1 from '@shared/components/js-func.component'; +import * as i6 from '@angular/material/button'; +import { ENTER, COMMA, SEMICOLON } from '@angular/cdk/keycodes'; +import * as i5$2 from '@angular/material/chips'; +import * as i6$1 from '@angular/material/icon'; +import * as i7$1 from '@shared/components/entity/entity-type-select.component'; +import * as i6$2 from '@shared/components/entity/entity-select.component'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import * as i9 from '@shared/components/tb-error.component'; +import * as i9$1 from '@angular/flex-layout/extended'; +import * as i12 from '@angular/material/tooltip'; +import { distinctUntilChanged, startWith, map, mergeMap, share } from 'rxjs/operators'; +import * as i7$2 from '@shared/components/tb-checkbox.component'; +import * as i5$3 from '@home/components/sms/sms-provider-configuration.component'; +import { HomeComponentsModule } from '@home/components/public-api'; +import * as i7$3 from '@shared/components/relation/relation-type-autocomplete.component'; +import * as i8$2 from '@shared/components/entity/entity-subtype-list.component'; +import * as i7$4 from '@home/components/relation/relation-filters.component'; +import { of } from 'rxjs'; +import * as i7$5 from '@angular/material/autocomplete'; +import * as i12$1 from '@shared/pipe/highlight.pipe'; +import * as i8$3 from '@shared/components/entity/entity-autocomplete.component'; +import * as i3$5 from '@shared/components/entity/entity-type-list.component'; + +class EmptyConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.emptyConfigForm; + } + onConfigurationSet(configuration) { + this.emptyConfigForm = this.fb.group({}); + } +} +EmptyConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EmptyConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +EmptyConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: EmptyConfigComponent, selector: "tb-node-empty-config", usesInheritance: true, ngImport: i0, template: '
        ', isInline: true }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EmptyConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-node-empty-config', + template: '
        ', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SafeHtmlPipe { + constructor(sanitizer) { + this.sanitizer = sanitizer; + } + transform(html) { + return this.sanitizer.bypassSecurityTrustHtml(html); + } +} +SafeHtmlPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); +SafeHtmlPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, name: "safeHtml" }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'safeHtml', + }] + }], ctorParameters: function () { return [{ type: i1$1.DomSanitizer }]; } }); + +class AssignCustomerConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.assignCustomerConfigForm; + } + onConfigurationSet(configuration) { + this.assignCustomerConfigForm = this.fb.group({ + customerNamePattern: [configuration ? configuration.customerNamePattern : null, [Validators.required, Validators.pattern(/.*\S.*/)]], + createCustomerIfNotExists: [configuration ? configuration.createCustomerIfNotExists : false, []], + customerCacheExpiration: [configuration ? configuration.customerCacheExpiration : null, [Validators.required, Validators.min(0)]] + }); + } + prepareOutputConfig(configuration) { + configuration.customerNamePattern = configuration.customerNamePattern.trim(); + return configuration; + } +} +AssignCustomerConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AssignCustomerConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +AssignCustomerConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AssignCustomerConfigComponent, selector: "tb-action-node-assign-to-customer-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ 'tb.rulenode.customer-name-pattern-required' | translate }}\n \n \n \n \n {{ 'tb.rulenode.create-customer-if-not-exists' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ 'tb.rulenode.customer-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.customer-cache-expiration-range' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AssignCustomerConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-assign-to-customer-config', + templateUrl: './assign-customer-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class AttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.attributeScopes = Object.keys(AttributeScope); + this.telemetryTypeTranslationsMap = telemetryTypeTranslations; + } + configForm() { + return this.attributesConfigForm; + } + onConfigurationSet(configuration) { + this.attributesConfigForm = this.fb.group({ + scope: [configuration ? configuration.scope : null, [Validators.required]], + notifyDevice: [configuration ? configuration.scope : true, []] + }); + } +} +AttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +AttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AttributesConfigComponent, selector: "tb-action-node-attributes-config", usesInheritance: true, ngImport: i0, template: "
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n \n {{ 'tb.rulenode.notify-device' | translate }}\n \n
        tb.rulenode.notify-device-hint
        \n
        \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-attributes-config', + templateUrl: './attributes-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +var OriginatorSource; +(function (OriginatorSource) { + OriginatorSource["CUSTOMER"] = "CUSTOMER"; + OriginatorSource["TENANT"] = "TENANT"; + OriginatorSource["RELATED"] = "RELATED"; + OriginatorSource["ALARM_ORIGINATOR"] = "ALARM_ORIGINATOR"; +})(OriginatorSource || (OriginatorSource = {})); +const originatorSourceTranslations = new Map([ + [OriginatorSource.CUSTOMER, 'tb.rulenode.originator-customer'], + [OriginatorSource.TENANT, 'tb.rulenode.originator-tenant'], + [OriginatorSource.RELATED, 'tb.rulenode.originator-related'], + [OriginatorSource.ALARM_ORIGINATOR, 'tb.rulenode.originator-alarm-originator'], +]); +var PerimeterType; +(function (PerimeterType) { + PerimeterType["CIRCLE"] = "CIRCLE"; + PerimeterType["POLYGON"] = "POLYGON"; +})(PerimeterType || (PerimeterType = {})); +const perimeterTypeTranslations = new Map([ + [PerimeterType.CIRCLE, 'tb.rulenode.perimeter-circle'], + [PerimeterType.POLYGON, 'tb.rulenode.perimeter-polygon'], +]); +var TimeUnit; +(function (TimeUnit) { + TimeUnit["MILLISECONDS"] = "MILLISECONDS"; + TimeUnit["SECONDS"] = "SECONDS"; + TimeUnit["MINUTES"] = "MINUTES"; + TimeUnit["HOURS"] = "HOURS"; + TimeUnit["DAYS"] = "DAYS"; +})(TimeUnit || (TimeUnit = {})); +const timeUnitTranslations = new Map([ + [TimeUnit.MILLISECONDS, 'tb.rulenode.time-unit-milliseconds'], + [TimeUnit.SECONDS, 'tb.rulenode.time-unit-seconds'], + [TimeUnit.MINUTES, 'tb.rulenode.time-unit-minutes'], + [TimeUnit.HOURS, 'tb.rulenode.time-unit-hours'], + [TimeUnit.DAYS, 'tb.rulenode.time-unit-days'] +]); +var RangeUnit; +(function (RangeUnit) { + RangeUnit["METER"] = "METER"; + RangeUnit["KILOMETER"] = "KILOMETER"; + RangeUnit["FOOT"] = "FOOT"; + RangeUnit["MILE"] = "MILE"; + RangeUnit["NAUTICAL_MILE"] = "NAUTICAL_MILE"; +})(RangeUnit || (RangeUnit = {})); +const rangeUnitTranslations = new Map([ + [RangeUnit.METER, 'tb.rulenode.range-unit-meter'], + [RangeUnit.KILOMETER, 'tb.rulenode.range-unit-kilometer'], + [RangeUnit.FOOT, 'tb.rulenode.range-unit-foot'], + [RangeUnit.MILE, 'tb.rulenode.range-unit-mile'], + [RangeUnit.NAUTICAL_MILE, 'tb.rulenode.range-unit-nautical-mile'] +]); +var EntityDetailsField; +(function (EntityDetailsField) { + EntityDetailsField["TITLE"] = "TITLE"; + EntityDetailsField["COUNTRY"] = "COUNTRY"; + EntityDetailsField["STATE"] = "STATE"; + EntityDetailsField["ZIP"] = "ZIP"; + EntityDetailsField["ADDRESS"] = "ADDRESS"; + EntityDetailsField["ADDRESS2"] = "ADDRESS2"; + EntityDetailsField["PHONE"] = "PHONE"; + EntityDetailsField["EMAIL"] = "EMAIL"; + EntityDetailsField["ADDITIONAL_INFO"] = "ADDITIONAL_INFO"; +})(EntityDetailsField || (EntityDetailsField = {})); +const entityDetailsTranslations = new Map([ + [EntityDetailsField.TITLE, 'tb.rulenode.entity-details-title'], + [EntityDetailsField.COUNTRY, 'tb.rulenode.entity-details-country'], + [EntityDetailsField.STATE, 'tb.rulenode.entity-details-state'], + [EntityDetailsField.ZIP, 'tb.rulenode.entity-details-zip'], + [EntityDetailsField.ADDRESS, 'tb.rulenode.entity-details-address'], + [EntityDetailsField.ADDRESS2, 'tb.rulenode.entity-details-address2'], + [EntityDetailsField.PHONE, 'tb.rulenode.entity-details-phone'], + [EntityDetailsField.EMAIL, 'tb.rulenode.entity-details-email'], + [EntityDetailsField.ADDITIONAL_INFO, 'tb.rulenode.entity-details-additional_info'] +]); +var FetchMode; +(function (FetchMode) { + FetchMode["FIRST"] = "FIRST"; + FetchMode["LAST"] = "LAST"; + FetchMode["ALL"] = "ALL"; +})(FetchMode || (FetchMode = {})); +var SamplingOrder; +(function (SamplingOrder) { + SamplingOrder["ASC"] = "ASC"; + SamplingOrder["DESC"] = "DESC"; +})(SamplingOrder || (SamplingOrder = {})); +var SqsQueueType; +(function (SqsQueueType) { + SqsQueueType["STANDARD"] = "STANDARD"; + SqsQueueType["FIFO"] = "FIFO"; +})(SqsQueueType || (SqsQueueType = {})); +const sqsQueueTypeTranslations = new Map([ + [SqsQueueType.STANDARD, 'tb.rulenode.sqs-queue-standard'], + [SqsQueueType.FIFO, 'tb.rulenode.sqs-queue-fifo'], +]); +const credentialsTypes = ['anonymous', 'basic', 'cert.PEM']; +const credentialsTypeTranslations = new Map([ + ['anonymous', 'tb.rulenode.credentials-anonymous'], + ['basic', 'tb.rulenode.credentials-basic'], + ['cert.PEM', 'tb.rulenode.credentials-pem'] +]); +const azureIotHubCredentialsTypes = ['sas', 'cert.PEM']; +const azureIotHubCredentialsTypeTranslations = new Map([ + ['sas', 'tb.rulenode.credentials-sas'], + ['cert.PEM', 'tb.rulenode.credentials-pem'] +]); +var HttpRequestType; +(function (HttpRequestType) { + HttpRequestType["GET"] = "GET"; + HttpRequestType["POST"] = "POST"; + HttpRequestType["PUT"] = "PUT"; + HttpRequestType["DELETE"] = "DELETE"; +})(HttpRequestType || (HttpRequestType = {})); +const ToByteStandartCharsetTypes = [ + 'US-ASCII', + 'ISO-8859-1', + 'UTF-8', + 'UTF-16BE', + 'UTF-16LE', + 'UTF-16' +]; +const ToByteStandartCharsetTypeTranslations = new Map([ + ['US-ASCII', 'tb.rulenode.charset-us-ascii'], + ['ISO-8859-1', 'tb.rulenode.charset-iso-8859-1'], + ['UTF-8', 'tb.rulenode.charset-utf-8'], + ['UTF-16BE', 'tb.rulenode.charset-utf-16be'], + ['UTF-16LE', 'tb.rulenode.charset-utf-16le'], + ['UTF-16', 'tb.rulenode.charset-utf-16'], +]); + +class AzureIotHubConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.allAzureIotHubCredentialsTypes = azureIotHubCredentialsTypes; + this.azureIotHubCredentialsTypeTranslationsMap = azureIotHubCredentialsTypeTranslations; + } + configForm() { + return this.azureIotHubConfigForm; + } + onConfigurationSet(configuration) { + this.azureIotHubConfigForm = this.fb.group({ + topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], + host: [configuration ? configuration.host : null, [Validators.required]], + port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], + connectTimeoutSec: [configuration ? configuration.connectTimeoutSec : null, + [Validators.required, Validators.min(1), Validators.max(200)]], + clientId: [configuration ? configuration.clientId : null, [Validators.required]], + cleanSession: [configuration ? configuration.cleanSession : false, []], + ssl: [configuration ? configuration.ssl : false, []], + credentials: this.fb.group({ + type: [configuration && configuration.credentials ? configuration.credentials.type : null, [Validators.required]], + sasKey: [configuration && configuration.credentials ? configuration.credentials.sasKey : null, []], + caCert: [configuration && configuration.credentials ? configuration.credentials.caCert : null, []], + caCertFileName: [configuration && configuration.credentials ? configuration.credentials.caCertFileName : null, []], + privateKey: [configuration && configuration.credentials ? configuration.credentials.privateKey : null, []], + privateKeyFileName: [configuration && configuration.credentials ? configuration.credentials.privateKeyFileName : null, []], + cert: [configuration && configuration.credentials ? configuration.credentials.cert : null, []], + certFileName: [configuration && configuration.credentials ? configuration.credentials.certFileName : null, []], + password: [configuration && configuration.credentials ? configuration.credentials.password : null, []], + }) + }); + } + prepareOutputConfig(configuration) { + const credentialsType = configuration.credentials.type; + if (credentialsType === 'sas') { + configuration.credentials = { + type: credentialsType, + sasKey: configuration.credentials.sasKey, + caCert: configuration.credentials.caCert, + caCertFileName: configuration.credentials.caCertFileName + }; + } + return configuration; + } + validatorTriggers() { + return ['credentials.type']; + } + updateValidators(emitEvent) { + const credentialsControl = this.azureIotHubConfigForm.get('credentials'); + const credentialsType = credentialsControl.get('type').value; + if (emitEvent) { + credentialsControl.reset({ type: credentialsType }, { emitEvent: false }); + } + credentialsControl.get('sasKey').setValidators([]); + credentialsControl.get('privateKey').setValidators([]); + credentialsControl.get('privateKeyFileName').setValidators([]); + credentialsControl.get('cert').setValidators([]); + credentialsControl.get('certFileName').setValidators([]); + switch (credentialsType) { + case 'sas': + credentialsControl.get('sasKey').setValidators([Validators.required]); + break; + case 'cert.PEM': + credentialsControl.get('privateKey').setValidators([Validators.required]); + credentialsControl.get('privateKeyFileName').setValidators([Validators.required]); + credentialsControl.get('cert').setValidators([Validators.required]); + credentialsControl.get('certFileName').setValidators([Validators.required]); + break; + } + credentialsControl.get('sasKey').updateValueAndValidity({ emitEvent }); + credentialsControl.get('privateKey').updateValueAndValidity({ emitEvent }); + credentialsControl.get('privateKeyFileName').updateValueAndValidity({ emitEvent }); + credentialsControl.get('cert').updateValueAndValidity({ emitEvent }); + credentialsControl.get('certFileName').updateValueAndValidity({ emitEvent }); + } +} +AzureIotHubConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AzureIotHubConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +AzureIotHubConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AzureIotHubConfigComponent, selector: "tb-action-node-azure-iot-hub-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.topic\n \n \n {{ 'tb.rulenode.topic-required' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ 'tb.rulenode.hostname-required' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ 'tb.rulenode.device-id-required' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get('credentials.type').value) | translate }}\n \n \n
        \n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ 'tb.rulenode.credentials-type-required' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ 'tb.rulenode.sas-key-required' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
        \n
        \n
        \n
        \n
        \n", styles: [":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["disabled", "expanded", "hideToggle", "togglePosition"], outputs: ["opened", "closed", "expandedChange", "afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { type: i4$2.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["tabIndex", "expandedHeight", "collapsedHeight"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i4$2.MatAccordion, selector: "mat-accordion", inputs: ["multi", "displayMode", "togglePosition", "hideToggle"], exportAs: ["matAccordion"] }, { type: i4$2.MatExpansionPanelTitle, selector: "mat-panel-title" }, { type: i4$2.MatExpansionPanelDescription, selector: "mat-panel-description" }, { type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AzureIotHubConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-azure-iot-hub-config', + templateUrl: './azure-iot-hub-config.component.html', + styleUrls: ['./mqtt-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class CheckPointConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.serviceType = ServiceType.TB_RULE_ENGINE; + } + configForm() { + return this.checkPointConfigForm; + } + onConfigurationSet(configuration) { + this.checkPointConfigForm = this.fb.group({ + queueName: [configuration ? configuration.queueName : null, [Validators.required]] + }); + } +} +CheckPointConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckPointConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CheckPointConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckPointConfigComponent, selector: "tb-action-node-check-point-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n
        \n", components: [{ type: i3$2.QueueTypeListComponent, selector: "tb-queue-type-list", inputs: ["required", "disabled", "queueType"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckPointConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-check-point-config', + templateUrl: './check-point-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class ClearAlarmConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.clearAlarmConfigForm; + } + onConfigurationSet(configuration) { + this.clearAlarmConfigForm = this.fb.group({ + alarmDetailsBuildJs: [configuration ? configuration.alarmDetailsBuildJs : null, [Validators.required]], + alarmType: [configuration ? configuration.alarmType : null, [Validators.required]] + }); + } + testScript() { + const script = this.clearAlarmConfigForm.get('alarmDetailsBuildJs').value; + this.nodeScriptTestService.testNodeScript(script, 'json', this.translate.instant('tb.rulenode.details'), 'Details', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/clear_alarm_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.clearAlarmConfigForm.get('alarmDetailsBuildJs').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +ClearAlarmConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ClearAlarmConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +ClearAlarmConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ClearAlarmConfigComponent, selector: "tb-action-node-clear-alarm-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n
        \n \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ 'tb.rulenode.alarm-type-required' | translate }}\n \n \n \n
        \n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ClearAlarmConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-clear-alarm-config', + templateUrl: './clear-alarm-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class CreateAlarmConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + this.alarmSeverities = Object.keys(AlarmSeverity); + this.alarmSeverityTranslationMap = alarmSeverityTranslations; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.createAlarmConfigForm; + } + onConfigurationSet(configuration) { + this.createAlarmConfigForm = this.fb.group({ + alarmDetailsBuildJs: [configuration ? configuration.alarmDetailsBuildJs : null, [Validators.required]], + useMessageAlarmData: [configuration ? configuration.useMessageAlarmData : false, []], + alarmType: [configuration ? configuration.alarmType : null, []], + severity: [configuration ? configuration.severity : null, []], + propagate: [configuration ? configuration.propagate : false, []], + relationTypes: [configuration ? configuration.relationTypes : null, []], + dynamicSeverity: false + }); + this.createAlarmConfigForm.get('dynamicSeverity').valueChanges.subscribe((dynamicSeverity) => { + if (dynamicSeverity) { + this.createAlarmConfigForm.get('severity').patchValue('', { emitEvent: false }); + } + else { + this.createAlarmConfigForm.get('severity').patchValue(this.alarmSeverities[0], { emitEvent: false }); + } + }); + } + validatorTriggers() { + return ['useMessageAlarmData']; + } + updateValidators(emitEvent) { + const useMessageAlarmData = this.createAlarmConfigForm.get('useMessageAlarmData').value; + if (useMessageAlarmData) { + this.createAlarmConfigForm.get('alarmType').setValidators([]); + this.createAlarmConfigForm.get('severity').setValidators([]); + } + else { + this.createAlarmConfigForm.get('alarmType').setValidators([Validators.required]); + this.createAlarmConfigForm.get('severity').setValidators([Validators.required]); + } + this.createAlarmConfigForm.get('alarmType').updateValueAndValidity({ emitEvent }); + this.createAlarmConfigForm.get('severity').updateValueAndValidity({ emitEvent }); + } + testScript() { + const script = this.createAlarmConfigForm.get('alarmDetailsBuildJs').value; + this.nodeScriptTestService.testNodeScript(script, 'json', this.translate.instant('tb.rulenode.details'), 'Details', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/create_alarm_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.createAlarmConfigForm.get('alarmDetailsBuildJs').setValue(theScript); + } + }); + } + removeKey(key, keysField) { + const keys = this.createAlarmConfigForm.get(keysField).value; + const index = keys.indexOf(key); + if (index >= 0) { + keys.splice(index, 1); + this.createAlarmConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + addKey(event, keysField) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let keys = this.createAlarmConfigForm.get(keysField).value; + if (!keys || keys.indexOf(value) === -1) { + if (!keys) { + keys = []; + } + keys.push(value); + this.createAlarmConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +CreateAlarmConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateAlarmConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +CreateAlarmConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CreateAlarmConfigComponent, selector: "tb-action-node-create-alarm-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n
        \n \n
        \n
        \n \n {{ 'tb.rulenode.use-message-alarm-data' | translate }}\n \n \n {{ 'tb.rulenode.use-dynamically-change-the-severity-of-alar' | translate }}\n \n
        \n
        \n
        \n \n tb.rulenode.alarm-type\n \n \n {{ 'tb.rulenode.alarm-type-required' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ 'tb.rulenode.alarm-severity-required' | translate }}\n \n \n \n {{ 'tb.rulenode.alarm-severity' | translate }}\n \n \n {{ 'tb.rulenode.alarm-severity-required' | translate }}\n \n \n \n
        \n \n {{ 'tb.rulenode.propagate' | translate }}\n \n
        \n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
        \n
        \n
        \n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateAlarmConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-create-alarm-config', + templateUrl: './create-alarm-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class CreateRelationConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.directionTypes = Object.keys(EntitySearchDirection); + this.directionTypeTranslations = entitySearchDirectionTranslations; + this.entityType = EntityType; + } + configForm() { + return this.createRelationConfigForm; + } + onConfigurationSet(configuration) { + this.createRelationConfigForm = this.fb.group({ + direction: [configuration ? configuration.direction : null, [Validators.required]], + entityType: [configuration ? configuration.entityType : null, [Validators.required]], + entityNamePattern: [configuration ? configuration.entityNamePattern : null, []], + entityTypePattern: [configuration ? configuration.entityTypePattern : null, []], + relationType: [configuration ? configuration.relationType : null, [Validators.required]], + createEntityIfNotExists: [configuration ? configuration.createEntityIfNotExists : false, []], + removeCurrentRelations: [configuration ? configuration.removeCurrentRelations : false, []], + changeOriginatorToRelatedEntity: [configuration ? configuration.changeOriginatorToRelatedEntity : false, []], + entityCacheExpiration: [configuration ? configuration.entityCacheExpiration : null, [Validators.required, Validators.min(0)]], + }); + } + validatorTriggers() { + return ['entityType']; + } + updateValidators(emitEvent) { + const entityType = this.createRelationConfigForm.get('entityType').value; + if (entityType) { + this.createRelationConfigForm.get('entityNamePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); + } + else { + this.createRelationConfigForm.get('entityNamePattern').setValidators([]); + } + if (entityType && (entityType === EntityType.DEVICE || entityType === EntityType.ASSET)) { + this.createRelationConfigForm.get('entityTypePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); + } + else { + this.createRelationConfigForm.get('entityTypePattern').setValidators([]); + } + this.createRelationConfigForm.get('entityNamePattern').updateValueAndValidity({ emitEvent }); + this.createRelationConfigForm.get('entityTypePattern').updateValueAndValidity({ emitEvent }); + } + prepareOutputConfig(configuration) { + configuration.entityNamePattern = configuration.entityNamePattern ? configuration.entityNamePattern.trim() : null; + configuration.entityTypePattern = configuration.entityTypePattern ? configuration.entityTypePattern.trim() : null; + return configuration; + } +} +CreateRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CreateRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CreateRelationConfigComponent, selector: "tb-action-node-create-relation-config", usesInheritance: true, ngImport: i0, template: "
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ 'tb.rulenode.entity-name-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ 'tb.rulenode.entity-type-pattern-required' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ 'tb.rulenode.relation-type-pattern-required' | translate }}\n \n \n \n
        \n \n {{ 'tb.rulenode.create-entity-if-not-exists' | translate }}\n \n
        tb.rulenode.create-entity-if-not-exists-hint
        \n
        \n \n {{ 'tb.rulenode.remove-current-relations' | translate }}\n \n
        tb.rulenode.remove-current-relations-hint
        \n \n {{ 'tb.rulenode.change-originator-to-related-entity' | translate }}\n \n
        tb.rulenode.change-originator-to-related-entity-hint
        \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ 'tb.rulenode.entity-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.entity-cache-expiration-range' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateRelationConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-create-relation-config', + templateUrl: './create-relation-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class DeleteRelationConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.directionTypes = Object.keys(EntitySearchDirection); + this.directionTypeTranslations = entitySearchDirectionTranslations; + this.entityType = EntityType; + } + configForm() { + return this.deleteRelationConfigForm; + } + onConfigurationSet(configuration) { + this.deleteRelationConfigForm = this.fb.group({ + deleteForSingleEntity: [configuration ? configuration.deleteForSingleEntity : false, []], + direction: [configuration ? configuration.direction : null, [Validators.required]], + entityType: [configuration ? configuration.entityType : null, []], + entityNamePattern: [configuration ? configuration.entityNamePattern : null, []], + relationType: [configuration ? configuration.relationType : null, [Validators.required]], + entityCacheExpiration: [configuration ? configuration.entityCacheExpiration : null, [Validators.required, Validators.min(0)]], + }); + } + validatorTriggers() { + return ['deleteForSingleEntity', 'entityType']; + } + updateValidators(emitEvent) { + const deleteForSingleEntity = this.deleteRelationConfigForm.get('deleteForSingleEntity').value; + const entityType = this.deleteRelationConfigForm.get('entityType').value; + if (deleteForSingleEntity) { + this.deleteRelationConfigForm.get('entityType').setValidators([Validators.required]); + } + else { + this.deleteRelationConfigForm.get('entityType').setValidators([]); + } + if (deleteForSingleEntity && entityType) { + this.deleteRelationConfigForm.get('entityNamePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); + } + else { + this.deleteRelationConfigForm.get('entityNamePattern').setValidators([]); + } + this.deleteRelationConfigForm.get('entityType').updateValueAndValidity({ emitEvent: false }); + this.deleteRelationConfigForm.get('entityNamePattern').updateValueAndValidity({ emitEvent }); + } + prepareOutputConfig(configuration) { + configuration.entityNamePattern = configuration.entityNamePattern ? configuration.entityNamePattern.trim() : null; + return configuration; + } +} +DeleteRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeleteRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +DeleteRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeleteRelationConfigComponent, selector: "tb-action-node-delete-relation-config", usesInheritance: true, ngImport: i0, template: "
        \n \n {{ 'tb.rulenode.delete-relation-to-specific-entity' | translate }}\n \n
        tb.rulenode.delete-relation-hint
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ 'tb.rulenode.entity-name-pattern-required' | translate }}\n \n \n \n
        \n \n tb.rulenode.relation-type-pattern\n \n \n {{ 'tb.rulenode.relation-type-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ 'tb.rulenode.entity-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.entity-cache-expiration-range' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeleteRelationConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-delete-relation-config', + templateUrl: './delete-relation-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class DeviceProfileConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.deviceProfile; + } + onConfigurationSet(configuration) { + this.deviceProfile = this.fb.group({ + persistAlarmRulesState: [configuration ? configuration.persistAlarmRulesState : false, Validators.required], + fetchAlarmRulesStateOnStart: [configuration ? configuration.fetchAlarmRulesStateOnStart : false, Validators.required] + }); + } +} +DeviceProfileConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceProfileConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +DeviceProfileConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceProfileConfigComponent, selector: "tb-device-profile-config", usesInheritance: true, ngImport: i0, template: "
        \n \n {{ 'tb.rulenode.persist-alarm-rules' | translate }}\n \n \n {{ 'tb.rulenode.fetch-alarm-rules' | translate }}\n \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceProfileConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-device-profile-config', + templateUrl: './device-profile-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class GeneratorConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.generatorConfigForm; + } + onConfigurationSet(configuration) { + this.generatorConfigForm = this.fb.group({ + msgCount: [configuration ? configuration.msgCount : null, [Validators.required, Validators.min(0)]], + periodInSeconds: [configuration ? configuration.periodInSeconds : null, [Validators.required, Validators.min(1)]], + originator: [configuration ? configuration.originator : null, []], + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + prepareInputConfig(configuration) { + if (configuration) { + if (configuration.originatorId && configuration.originatorType) { + configuration.originator = { + id: configuration.originatorId, entityType: configuration.originatorType + }; + } + else { + configuration.originator = null; + } + delete configuration.originatorId; + delete configuration.originatorType; + } + return configuration; + } + prepareOutputConfig(configuration) { + if (configuration.originator) { + configuration.originatorId = configuration.originator.id; + configuration.originatorType = configuration.originator.entityType; + } + else { + configuration.originatorId = null; + configuration.originatorType = null; + } + delete configuration.originator; + return configuration; + } + testScript() { + const script = this.generatorConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'generate', this.translate.instant('tb.rulenode.generator'), 'Generate', ['prevMsg', 'prevMetadata', 'prevMsgType'], this.ruleNodeId, 'rulenode/generator_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.generatorConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +GeneratorConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GeneratorConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +GeneratorConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GeneratorConfigComponent, selector: "tb-action-node-generator-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.message-count\n \n \n {{ 'tb.rulenode.message-count-required' | translate }}\n \n \n {{ 'tb.rulenode.min-message-count-message' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ 'tb.rulenode.period-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-period-seconds-message' | translate }}\n \n \n
        \n \n \n \n
        \n \n \n \n
        \n \n
        \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i6$2.EntitySelectComponent, selector: "tb-entity-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "required", "disabled"] }, { type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GeneratorConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-generator-config', + templateUrl: './generator-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class GpsGeoActionConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.perimeterType = PerimeterType; + this.perimeterTypes = Object.keys(PerimeterType); + this.perimeterTypeTranslationMap = perimeterTypeTranslations; + this.rangeUnits = Object.keys(RangeUnit); + this.rangeUnitTranslationMap = rangeUnitTranslations; + this.timeUnits = Object.keys(TimeUnit); + this.timeUnitsTranslationMap = timeUnitTranslations; + } + configForm() { + return this.geoActionConfigForm; + } + onConfigurationSet(configuration) { + this.geoActionConfigForm = this.fb.group({ + latitudeKeyName: [configuration ? configuration.latitudeKeyName : null, [Validators.required]], + longitudeKeyName: [configuration ? configuration.longitudeKeyName : null, [Validators.required]], + fetchPerimeterInfoFromMessageMetadata: [configuration ? configuration.fetchPerimeterInfoFromMessageMetadata : false, []], + perimeterType: [configuration ? configuration.perimeterType : null, []], + centerLatitude: [configuration ? configuration.centerLatitude : null, []], + centerLongitude: [configuration ? configuration.centerLatitude : null, []], + range: [configuration ? configuration.range : null, []], + rangeUnit: [configuration ? configuration.rangeUnit : null, []], + polygonsDefinition: [configuration ? configuration.polygonsDefinition : null, []], + minInsideDuration: [configuration ? configuration.minInsideDuration : null, + [Validators.required, Validators.min(1), Validators.max(2147483647)]], + minInsideDurationTimeUnit: [configuration ? configuration.minInsideDurationTimeUnit : null, [Validators.required]], + minOutsideDuration: [configuration ? configuration.minOutsideDuration : null, + [Validators.required, Validators.min(1), Validators.max(2147483647)]], + minOutsideDurationTimeUnit: [configuration ? configuration.minOutsideDurationTimeUnit : null, [Validators.required]], + }); + } + validatorTriggers() { + return ['fetchPerimeterInfoFromMessageMetadata', 'perimeterType']; + } + updateValidators(emitEvent) { + const fetchPerimeterInfoFromMessageMetadata = this.geoActionConfigForm.get('fetchPerimeterInfoFromMessageMetadata').value; + const perimeterType = this.geoActionConfigForm.get('perimeterType').value; + if (fetchPerimeterInfoFromMessageMetadata) { + this.geoActionConfigForm.get('perimeterType').setValidators([]); + } + else { + this.geoActionConfigForm.get('perimeterType').setValidators([Validators.required]); + } + if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.CIRCLE) { + this.geoActionConfigForm.get('centerLatitude').setValidators([Validators.required, + Validators.min(-90), Validators.max(90)]); + this.geoActionConfigForm.get('centerLongitude').setValidators([Validators.required, + Validators.min(-180), Validators.max(180)]); + this.geoActionConfigForm.get('range').setValidators([Validators.required, Validators.min(0)]); + this.geoActionConfigForm.get('rangeUnit').setValidators([Validators.required]); + } + else { + this.geoActionConfigForm.get('centerLatitude').setValidators([]); + this.geoActionConfigForm.get('centerLongitude').setValidators([]); + this.geoActionConfigForm.get('range').setValidators([]); + this.geoActionConfigForm.get('rangeUnit').setValidators([]); + } + if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.POLYGON) { + this.geoActionConfigForm.get('polygonsDefinition').setValidators([Validators.required]); + } + else { + this.geoActionConfigForm.get('polygonsDefinition').setValidators([]); + } + this.geoActionConfigForm.get('perimeterType').updateValueAndValidity({ emitEvent: false }); + this.geoActionConfigForm.get('centerLatitude').updateValueAndValidity({ emitEvent }); + this.geoActionConfigForm.get('centerLongitude').updateValueAndValidity({ emitEvent }); + this.geoActionConfigForm.get('range').updateValueAndValidity({ emitEvent }); + this.geoActionConfigForm.get('rangeUnit').updateValueAndValidity({ emitEvent }); + this.geoActionConfigForm.get('polygonsDefinition').updateValueAndValidity({ emitEvent }); + } +} +GpsGeoActionConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoActionConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +GpsGeoActionConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GpsGeoActionConfigComponent, selector: "tb-action-node-gps-geofencing-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ 'tb.rulenode.latitude-key-name-required' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ 'tb.rulenode.longitude-key-name-required' | translate }}\n \n \n \n {{ 'tb.rulenode.fetch-perimeter-info-from-message-metadata' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ 'tb.rulenode.circle-center-latitude-required' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ 'tb.rulenode.circle-center-longitude-required' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ 'tb.rulenode.range-required' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ 'tb.rulenode.polygon-definition-required' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.min-inside-duration\n \n \n {{ 'tb.rulenode.min-inside-duration-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.min-outside-duration\n \n \n {{ 'tb.rulenode.min-outside-duration-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoActionConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-gps-geofencing-config', + templateUrl: './gps-geo-action-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class KvMapConfigComponent extends PageComponent { + constructor(store, translate, injector, fb) { + super(store); + this.store = store; + this.translate = translate; + this.injector = injector; + this.fb = fb; + this.propagateChange = null; + this.valueChangeSubscription = null; + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + ngOnInit() { + this.ngControl = this.injector.get(NgControl); + if (this.ngControl != null) { + this.ngControl.valueAccessor = this; + } + this.kvListFormGroup = this.fb.group({}); + this.kvListFormGroup.addControl('keyVals', this.fb.array([])); + } + keyValsFormArray() { + return this.kvListFormGroup.get('keyVals'); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + setDisabledState(isDisabled) { + this.disabled = isDisabled; + if (this.disabled) { + this.kvListFormGroup.disable({ emitEvent: false }); + } + else { + this.kvListFormGroup.enable({ emitEvent: false }); + } + } + writeValue(keyValMap) { + if (this.valueChangeSubscription) { + this.valueChangeSubscription.unsubscribe(); + } + const keyValsControls = []; + if (keyValMap) { + for (const property of Object.keys(keyValMap)) { + if (Object.prototype.hasOwnProperty.call(keyValMap, property)) { + keyValsControls.push(this.fb.group({ + key: [property, [Validators.required]], + value: [keyValMap[property], [Validators.required]] + })); + } + } + } + this.kvListFormGroup.setControl('keyVals', this.fb.array(keyValsControls)); + this.valueChangeSubscription = this.kvListFormGroup.valueChanges.subscribe(() => { + this.updateModel(); + }); + } + removeKeyVal(index) { + this.kvListFormGroup.get('keyVals').removeAt(index); + } + addKeyVal() { + const keyValsFormArray = this.kvListFormGroup.get('keyVals'); + keyValsFormArray.push(this.fb.group({ + key: ['', [Validators.required]], + value: ['', [Validators.required]] + })); + } + validate(c) { + const kvList = this.kvListFormGroup.get('keyVals').value; + if (!kvList.length && this.required) { + return { + kvMapRequired: true + }; + } + if (!this.kvListFormGroup.valid) { + return { + kvFieldsRequired: true + }; + } + return null; + } + updateModel() { + const kvList = this.kvListFormGroup.get('keyVals').value; + if (this.required && !kvList.length || !this.kvListFormGroup.valid) { + this.propagateChange(null); + } + else { + const keyValMap = {}; + kvList.forEach((entry) => { + keyValMap[entry.key] = entry.value; + }); + this.propagateChange(keyValMap); + } + } +} +KvMapConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KvMapConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i0.Injector }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +KvMapConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: { disabled: "disabled", requiredText: "requiredText", keyText: "keyText", keyRequiredText: "keyRequiredText", valText: "valText", valRequiredText: "valRequiredText", required: "required" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => KvMapConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => KvMapConfigComponent), + multi: true, + } + ], usesInheritance: true, ngImport: i0, template: "
        \n
        \n {{ keyText | translate }}\n {{ valText | translate }}\n \n
        \n
        \n
        \n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
        \n
        \n \n
        \n \n
        \n
        \n", styles: [":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i9$1.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i12.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KvMapConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-kv-map-config', + templateUrl: './kv-map-config.component.html', + styleUrls: ['./kv-map-config.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => KvMapConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => KvMapConfigComponent), + multi: true, + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i0.Injector }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ + type: Input + }], requiredText: [{ + type: Input + }], keyText: [{ + type: Input + }], keyRequiredText: [{ + type: Input + }], valText: [{ + type: Input + }], valRequiredText: [{ + type: Input + }], required: [{ + type: Input + }] } }); + +class KafkaConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.ackValues = ['all', '-1', '0', '1']; + this.ToByteStandartCharsetTypesValues = ToByteStandartCharsetTypes; + this.ToByteStandartCharsetTypeTranslationMap = ToByteStandartCharsetTypeTranslations; + } + configForm() { + return this.kafkaConfigForm; + } + onConfigurationSet(configuration) { + this.kafkaConfigForm = this.fb.group({ + topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], + bootstrapServers: [configuration ? configuration.bootstrapServers : null, [Validators.required]], + retries: [configuration ? configuration.retries : null, [Validators.min(0)]], + batchSize: [configuration ? configuration.batchSize : null, [Validators.min(0)]], + linger: [configuration ? configuration.linger : null, [Validators.min(0)]], + bufferMemory: [configuration ? configuration.bufferMemory : null, [Validators.min(0)]], + acks: [configuration ? configuration.acks : null, [Validators.required]], + keySerializer: [configuration ? configuration.keySerializer : null, [Validators.required]], + valueSerializer: [configuration ? configuration.valueSerializer : null, [Validators.required]], + otherProperties: [configuration ? configuration.otherProperties : null, []], + addMetadataKeyValuesAsKafkaHeaders: [configuration ? configuration.addMetadataKeyValuesAsKafkaHeaders : false, []], + kafkaHeadersCharset: [configuration ? configuration.kafkaHeadersCharset : null, []] + }); + } + validatorTriggers() { + return ['addMetadataKeyValuesAsKafkaHeaders']; + } + updateValidators(emitEvent) { + const addMetadataKeyValuesAsKafkaHeaders = this.kafkaConfigForm.get('addMetadataKeyValuesAsKafkaHeaders').value; + if (addMetadataKeyValuesAsKafkaHeaders) { + this.kafkaConfigForm.get('kafkaHeadersCharset').setValidators([Validators.required]); + } + else { + this.kafkaConfigForm.get('kafkaHeadersCharset').setValidators([]); + } + this.kafkaConfigForm.get('kafkaHeadersCharset').updateValueAndValidity({ emitEvent }); + } +} +KafkaConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KafkaConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +KafkaConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: KafkaConfigComponent, selector: "tb-action-node-kafka-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.topic-pattern\n \n \n {{ 'tb.rulenode.topic-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ 'tb.rulenode.bootstrap-servers-required' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ 'tb.rulenode.min-retries-message' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ 'tb.rulenode.min-batch-size-bytes-message' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ 'tb.rulenode.min-linger-ms-message' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ 'tb.rulenode.min-buffer-memory-bytes-message' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ 'tb.rulenode.key-serializer-required' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ 'tb.rulenode.value-serializer-required' | translate }}\n \n \n \n \n \n \n {{ 'tb.rulenode.add-metadata-key-values-as-kafka-headers' | translate }}\n \n
        tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
        \n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KafkaConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-kafka-config', + templateUrl: './kafka-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class LogConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.logConfigForm; + } + onConfigurationSet(configuration) { + this.logConfigForm = this.fb.group({ + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + testScript() { + const script = this.logConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'string', this.translate.instant('tb.rulenode.to-string'), 'ToString', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/log_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.logConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +LogConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: LogConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +LogConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: LogConfigComponent, selector: "tb-action-node-log-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n
        \n \n
        \n
        \n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: LogConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-log-config', + templateUrl: './log-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class CredentialsConfigComponent extends PageComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.subscriptions = []; + this.disableCertPemCredentials = false; + this.passwordFieldRquired = true; + this.allCredentialsTypes = credentialsTypes; + this.credentialsTypeTranslationsMap = credentialsTypeTranslations; + this.propagateChange = null; + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + ngOnInit() { + this.credentialsConfigFormGroup = this.fb.group({ + type: [null, [Validators.required]], + username: [null, []], + password: [null, []], + caCert: [null, []], + caCertFileName: [null, []], + privateKey: [null, []], + privateKeyFileName: [null, []], + cert: [null, []], + certFileName: [null, []] + }); + this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(distinctUntilChanged()).subscribe(() => { + this.updateView(); + })); + this.subscriptions.push(this.credentialsConfigFormGroup.get('type').valueChanges.subscribe(() => { + this.credentialsTypeChanged(); + })); + } + ngOnChanges(changes) { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue) { + if (change.currentValue && propName === 'disableCertPemCredentials') { + const credentialsTypeValue = this.credentialsConfigFormGroup.get('type').value; + if (credentialsTypeValue === 'cert.PEM') { + setTimeout(() => { + this.credentialsConfigFormGroup.get('type').patchValue('anonymous', { emitEvent: true }); + }); + } + } + } + } + } + ngOnDestroy() { + this.subscriptions.forEach(s => s.unsubscribe()); + } + writeValue(credentials) { + if (isDefinedAndNotNull(credentials)) { + this.credentialsConfigFormGroup.reset(credentials, { emitEvent: false }); + this.updateValidators(false); + } + } + setDisabledState(isDisabled) { + if (isDisabled) { + this.credentialsConfigFormGroup.disable(); + } + else { + this.credentialsConfigFormGroup.enable(); + this.updateValidators(); + } + } + updateView() { + let credentialsConfigValue = this.credentialsConfigFormGroup.value; + const credentialsTypeValue = credentialsConfigValue.type; + switch (credentialsTypeValue) { + case 'anonymous': + credentialsConfigValue = { + type: credentialsTypeValue + }; + break; + case 'basic': + credentialsConfigValue = { + type: credentialsTypeValue, + username: credentialsConfigValue.username, + password: credentialsConfigValue.password, + }; + break; + case 'cert.PEM': + delete credentialsConfigValue.username; + break; + } + this.propagateChange(credentialsConfigValue); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + validate(c) { + return this.credentialsConfigFormGroup.valid ? null : { + credentialsConfig: { + valid: false, + }, + }; + } + credentialsTypeChanged() { + this.credentialsConfigFormGroup.patchValue({ + username: null, + password: null, + caCert: null, + caCertFileName: null, + privateKey: null, + privateKeyFileName: null, + cert: null, + certFileName: null, + }); + this.updateValidators(); + } + updateValidators(emitEvent = false) { + const credentialsTypeValue = this.credentialsConfigFormGroup.get('type').value; + if (emitEvent) { + this.credentialsConfigFormGroup.reset({ type: credentialsTypeValue }, { emitEvent: false }); + } + this.credentialsConfigFormGroup.setValidators([]); + this.credentialsConfigFormGroup.get('username').setValidators([]); + this.credentialsConfigFormGroup.get('password').setValidators([]); + switch (credentialsTypeValue) { + case 'anonymous': + break; + case 'basic': + this.credentialsConfigFormGroup.get('username').setValidators([Validators.required]); + this.credentialsConfigFormGroup.get('password').setValidators(this.passwordFieldRquired ? [Validators.required] : []); + break; + case 'cert.PEM': + this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(Validators.required, [['caCert', 'caCertFileName'], ['privateKey', 'privateKeyFileName', 'cert', 'certFileName']])]); + break; + } + this.credentialsConfigFormGroup.get('username').updateValueAndValidity({ emitEvent }); + this.credentialsConfigFormGroup.get('password').updateValueAndValidity({ emitEvent }); + this.credentialsConfigFormGroup.updateValueAndValidity({ emitEvent }); + } + requiredFilesSelected(validator, requiredFieldsSet = null) { + return (group) => { + if (!requiredFieldsSet) { + requiredFieldsSet = [Object.keys(group.controls)]; + } + const allRequiredFilesSelected = (group === null || group === void 0 ? void 0 : group.controls) && + requiredFieldsSet.some(arrFields => arrFields.every(k => !validator(group.controls[k]))); + return allRequiredFilesSelected ? null : { notAllRequiredFilesSelected: true }; + }; + } +} +CredentialsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CredentialsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CredentialsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: { required: "required", disableCertPemCredentials: "disableCertPemCredentials", passwordFieldRquired: "passwordFieldRquired" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CredentialsConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => CredentialsConfigComponent), + multi: true, + } + ], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "
        \n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get('type').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ 'tb.rulenode.credentials-type-required' | translate }}\n \n \n
        \n \n \n \n \n tb.rulenode.username\n \n \n {{ 'tb.rulenode.username-required' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ 'tb.rulenode.password-required' | translate }}\n \n \n \n \n
        {{ 'tb.rulenode.credentials-pem-hint' | translate }}
        \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
        \n
        \n
        \n
        \n
        \n", components: [{ type: i4$2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["disabled", "expanded", "hideToggle", "togglePosition"], outputs: ["opened", "closed", "expandedChange", "afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { type: i4$2.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["tabIndex", "expandedHeight", "collapsedHeight"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4$2.MatExpansionPanelTitle, selector: "mat-panel-title" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i4$2.MatExpansionPanelDescription, selector: "mat-panel-description" }, { type: i4$2.MatExpansionPanelContent, selector: "ng-template[matExpansionPanelContent]" }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CredentialsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-credentials-config', + templateUrl: './credentials-config.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CredentialsConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => CredentialsConfigComponent), + multi: true, + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { required: [{ + type: Input + }], disableCertPemCredentials: [{ + type: Input + }], passwordFieldRquired: [{ + type: Input + }] } }); + +class MqttConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.mqttConfigForm; + } + onConfigurationSet(configuration) { + this.mqttConfigForm = this.fb.group({ + topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], + host: [configuration ? configuration.host : null, [Validators.required]], + port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], + connectTimeoutSec: [configuration ? configuration.connectTimeoutSec : null, + [Validators.required, Validators.min(1), Validators.max(200)]], + clientId: [configuration ? configuration.clientId : null, []], + cleanSession: [configuration ? configuration.cleanSession : false, []], + ssl: [configuration ? configuration.ssl : false, []], + credentials: [configuration ? configuration.credentials : null, []] + }); + } +} +MqttConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MqttConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MqttConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MqttConfigComponent, selector: "tb-action-node-mqtt-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.topic-pattern\n \n \n {{ 'tb.rulenode.topic-pattern-required' | translate }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ 'tb.rulenode.host-required' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ 'tb.rulenode.port-required' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ 'tb.rulenode.connect-timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.connect-timeout-range' | translate }}\n \n \n {{ 'tb.rulenode.connect-timeout-range' | translate }}\n \n \n
        \n \n tb.rulenode.client-id\n \n \n
        tb.rulenode.client-id-hint
        \n \n {{ 'tb.rulenode.clean-session' | translate }}\n \n \n {{ 'tb.rulenode.enable-ssl' | translate }}\n \n \n
        \n", styles: [":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: ["required", "disableCertPemCredentials", "passwordFieldRquired"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MqttConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-mqtt-config', + templateUrl: './mqtt-config.component.html', + styleUrls: ['./mqtt-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class MsgCountConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.msgCountConfigForm; + } + onConfigurationSet(configuration) { + this.msgCountConfigForm = this.fb.group({ + interval: [configuration ? configuration.interval : null, [Validators.required, Validators.min(1)]], + telemetryPrefix: [configuration ? configuration.telemetryPrefix : null, [Validators.required]] + }); + } +} +MsgCountConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgCountConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MsgCountConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MsgCountConfigComponent, selector: "tb-action-node-msg-count-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.interval-seconds\n \n \n {{ 'tb.rulenode.interval-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-interval-seconds-message' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ 'tb.rulenode.output-timeseries-key-prefix-required' | translate }}\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgCountConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-msg-count-config', + templateUrl: './msg-count-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class MsgDelayConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.msgDelayConfigForm; + } + onConfigurationSet(configuration) { + this.msgDelayConfigForm = this.fb.group({ + useMetadataPeriodInSecondsPatterns: [configuration ? configuration.useMetadataPeriodInSecondsPatterns : false, []], + periodInSeconds: [configuration ? configuration.periodInSeconds : null, []], + periodInSecondsPattern: [configuration ? configuration.periodInSecondsPattern : null, []], + maxPendingMsgs: [configuration ? configuration.maxPendingMsgs : null, + [Validators.required, Validators.min(1), Validators.max(100000)]], + }); + } + validatorTriggers() { + return ['useMetadataPeriodInSecondsPatterns']; + } + updateValidators(emitEvent) { + const useMetadataPeriodInSecondsPatterns = this.msgDelayConfigForm.get('useMetadataPeriodInSecondsPatterns').value; + if (useMetadataPeriodInSecondsPatterns) { + this.msgDelayConfigForm.get('periodInSecondsPattern').setValidators([Validators.required]); + this.msgDelayConfigForm.get('periodInSeconds').setValidators([]); + } + else { + this.msgDelayConfigForm.get('periodInSecondsPattern').setValidators([]); + this.msgDelayConfigForm.get('periodInSeconds').setValidators([Validators.required, Validators.min(0)]); + } + this.msgDelayConfigForm.get('periodInSecondsPattern').updateValueAndValidity({ emitEvent }); + this.msgDelayConfigForm.get('periodInSeconds').updateValueAndValidity({ emitEvent }); + } +} +MsgDelayConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgDelayConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MsgDelayConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MsgDelayConfigComponent, selector: "tb-action-node-msg-delay-config", usesInheritance: true, ngImport: i0, template: "
        \n \n {{ 'tb.rulenode.use-metadata-period-in-seconds-patterns' | translate }}\n \n
        tb.rulenode.use-metadata-period-in-seconds-patterns-hint
        \n \n tb.rulenode.period-seconds\n \n \n {{ 'tb.rulenode.period-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-period-0-seconds-message' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ 'tb.rulenode.period-in-seconds-pattern-required' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ 'tb.rulenode.max-pending-messages-required' | translate }}\n \n \n {{ 'tb.rulenode.max-pending-messages-range' | translate }}\n \n \n {{ 'tb.rulenode.max-pending-messages-range' | translate }}\n \n \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgDelayConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-msg-delay-config', + templateUrl: './msg-delay-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class PubSubConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.pubSubConfigForm; + } + onConfigurationSet(configuration) { + this.pubSubConfigForm = this.fb.group({ + projectId: [configuration ? configuration.projectId : null, [Validators.required]], + topicName: [configuration ? configuration.topicName : null, [Validators.required]], + serviceAccountKey: [configuration ? configuration.serviceAccountKey : null, [Validators.required]], + serviceAccountKeyFileName: [configuration ? configuration.serviceAccountKeyFileName : null, [Validators.required]], + messageAttributes: [configuration ? configuration.messageAttributes : null, []] + }); + } +} +PubSubConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PubSubConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +PubSubConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PubSubConfigComponent, selector: "tb-action-node-pub-sub-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.gcp-project-id\n \n \n {{ 'tb.rulenode.gcp-project-id-required' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ 'tb.rulenode.pubsub-topic-name-required' | translate }}\n \n \n \n \n \n
        \n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PubSubConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-pub-sub-config', + templateUrl: './pubsub-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class PushToCloudConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.attributeScopes = Object.keys(AttributeScope); + this.telemetryTypeTranslationsMap = telemetryTypeTranslations; + } + configForm() { + return this.pushToCloudConfigForm; + } + onConfigurationSet(configuration) { + this.pushToCloudConfigForm = this.fb.group({ + scope: [configuration ? configuration.scope : null, [Validators.required]] + }); + } +} +PushToCloudConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToCloudConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +PushToCloudConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PushToCloudConfigComponent, selector: "tb-action-node-push-to-cloud-config", usesInheritance: true, ngImport: i0, template: "
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToCloudConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-push-to-cloud-config', + templateUrl: './push-to-cloud-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class PushToEdgeConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.attributeScopes = Object.keys(AttributeScope); + this.telemetryTypeTranslationsMap = telemetryTypeTranslations; + } + configForm() { + return this.pushToEdgeConfigForm; + } + onConfigurationSet(configuration) { + this.pushToEdgeConfigForm = this.fb.group({ + scope: [configuration ? configuration.scope : null, [Validators.required]] + }); + } +} +PushToEdgeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToEdgeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +PushToEdgeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PushToEdgeConfigComponent, selector: "tb-action-node-push-to-edge-config", usesInheritance: true, ngImport: i0, template: "
        \n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToEdgeConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-push-to-edge-config', + templateUrl: './push-to-edge-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RabbitMqConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.messageProperties = [ + null, + 'BASIC', + 'TEXT_PLAIN', + 'MINIMAL_BASIC', + 'MINIMAL_PERSISTENT_BASIC', + 'PERSISTENT_BASIC', + 'PERSISTENT_TEXT_PLAIN' + ]; + } + configForm() { + return this.rabbitMqConfigForm; + } + onConfigurationSet(configuration) { + this.rabbitMqConfigForm = this.fb.group({ + exchangeNamePattern: [configuration ? configuration.exchangeNamePattern : null, []], + routingKeyPattern: [configuration ? configuration.routingKeyPattern : null, []], + messageProperties: [configuration ? configuration.messageProperties : null, []], + host: [configuration ? configuration.host : null, [Validators.required]], + port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], + virtualHost: [configuration ? configuration.virtualHost : null, []], + username: [configuration ? configuration.username : null, []], + password: [configuration ? configuration.password : null, []], + automaticRecoveryEnabled: [configuration ? configuration.automaticRecoveryEnabled : false, []], + connectionTimeout: [configuration ? configuration.connectionTimeout : null, [Validators.min(0)]], + handshakeTimeout: [configuration ? configuration.handshakeTimeout : null, [Validators.min(0)]], + clientProperties: [configuration ? configuration.clientProperties : null, []] + }); + } +} +RabbitMqConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RabbitMqConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RabbitMqConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RabbitMqConfigComponent, selector: "tb-action-node-rabbit-mq-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
        \n \n tb.rulenode.host\n \n \n {{ 'tb.rulenode.host-required' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ 'tb.rulenode.port-required' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n
        \n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ 'tb.rulenode.automatic-recovery' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ 'tb.rulenode.min-connection-timeout-ms-message' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ 'tb.rulenode.min-handshake-timeout-ms-message' | translate }}\n \n \n \n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RabbitMqConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-rabbit-mq-config', + templateUrl: './rabbit-mq-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RestApiCallConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.proxySchemes = ['http', 'https']; + this.httpRequestTypes = Object.keys(HttpRequestType); + } + configForm() { + return this.restApiCallConfigForm; + } + onConfigurationSet(configuration) { + this.restApiCallConfigForm = this.fb.group({ + restEndpointUrlPattern: [configuration ? configuration.restEndpointUrlPattern : null, [Validators.required]], + requestMethod: [configuration ? configuration.requestMethod : null, [Validators.required]], + useSimpleClientHttpFactory: [configuration ? configuration.useSimpleClientHttpFactory : false, []], + ignoreRequestBody: [configuration ? configuration.ignoreRequestBody : false, []], + enableProxy: [configuration ? configuration.enableProxy : false, []], + useSystemProxyProperties: [configuration ? configuration.enableProxy : false, []], + proxyScheme: [configuration ? configuration.proxyHost : null, []], + proxyHost: [configuration ? configuration.proxyHost : null, []], + proxyPort: [configuration ? configuration.proxyPort : null, []], + proxyUser: [configuration ? configuration.proxyUser : null, []], + proxyPassword: [configuration ? configuration.proxyPassword : null, []], + readTimeoutMs: [configuration ? configuration.readTimeoutMs : null, []], + maxParallelRequestsCount: [configuration ? configuration.maxParallelRequestsCount : null, [Validators.min(0)]], + headers: [configuration ? configuration.headers : null, []], + useRedisQueueForMsgPersistence: [configuration ? configuration.useRedisQueueForMsgPersistence : false, []], + trimQueue: [configuration ? configuration.trimQueue : false, []], + maxQueueSize: [configuration ? configuration.maxQueueSize : null, []], + credentials: [configuration ? configuration.credentials : null, []] + }); + } + validatorTriggers() { + return ['useSimpleClientHttpFactory', 'useRedisQueueForMsgPersistence', 'enableProxy', 'useSystemProxyProperties']; + } + updateValidators(emitEvent) { + const useSimpleClientHttpFactory = this.restApiCallConfigForm.get('useSimpleClientHttpFactory').value; + const useRedisQueueForMsgPersistence = this.restApiCallConfigForm.get('useRedisQueueForMsgPersistence').value; + const enableProxy = this.restApiCallConfigForm.get('enableProxy').value; + const useSystemProxyProperties = this.restApiCallConfigForm.get('useSystemProxyProperties').value; + if (enableProxy && !useSystemProxyProperties) { + this.restApiCallConfigForm.get('proxyHost').setValidators(enableProxy ? [Validators.required] : []); + this.restApiCallConfigForm.get('proxyPort').setValidators(enableProxy ? + [Validators.required, Validators.min(1), Validators.max(65535)] : []); + } + else { + this.restApiCallConfigForm.get('proxyHost').setValidators([]); + this.restApiCallConfigForm.get('proxyPort').setValidators([]); + if (useSimpleClientHttpFactory) { + this.restApiCallConfigForm.get('readTimeoutMs').setValidators([]); + } + else { + this.restApiCallConfigForm.get('readTimeoutMs').setValidators([Validators.min(0)]); + } + } + if (useRedisQueueForMsgPersistence) { + this.restApiCallConfigForm.get('maxQueueSize').setValidators([Validators.min(0)]); + } + else { + this.restApiCallConfigForm.get('maxQueueSize').setValidators([]); + } + this.restApiCallConfigForm.get('readTimeoutMs').updateValueAndValidity({ emitEvent }); + this.restApiCallConfigForm.get('maxQueueSize').updateValueAndValidity({ emitEvent }); + this.restApiCallConfigForm.get('proxyHost').updateValueAndValidity({ emitEvent }); + this.restApiCallConfigForm.get('proxyPort').updateValueAndValidity({ emitEvent }); + this.restApiCallConfigForm.get('credentials').updateValueAndValidity({ emitEvent }); + } +} +RestApiCallConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RestApiCallConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RestApiCallConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RestApiCallConfigComponent, selector: "tb-action-node-rest-api-call-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ 'tb.rulenode.endpoint-url-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ 'tb.rulenode.enable-proxy' | translate }}\n \n \n {{ 'tb.rulenode.use-simple-client-http-factory' | translate }}\n \n \n {{ 'tb.rulenode.ignore-request-body' | translate }}\n \n
        \n \n {{ 'tb.rulenode.use-system-proxy-properties' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ 'tb.rulenode.proxy-host-required' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ 'tb.rulenode.proxy-port-required' | translate }}\n \n \n {{ 'tb.rulenode.proxy-port-range' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n
        \n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
        \n \n \n \n {{ 'tb.rulenode.use-redis-queue' | translate }}\n \n
        \n \n {{ 'tb.rulenode.trim-redis-queue' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
        \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }, { type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: ["required", "disableCertPemCredentials", "passwordFieldRquired"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RestApiCallConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-rest-api-call-config', + templateUrl: './rest-api-call-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RpcReplyConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.rpcReplyConfigForm; + } + onConfigurationSet(configuration) { + this.rpcReplyConfigForm = this.fb.group({ + requestIdMetaDataAttribute: [configuration ? configuration.requestIdMetaDataAttribute : null, []] + }); + } +} +RpcReplyConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcReplyConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RpcReplyConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RpcReplyConfigComponent, selector: "tb-action-node-rpc-reply-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.request-id-metadata-attribute\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcReplyConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-rpc-reply-config', + templateUrl: './rpc-reply-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RpcRequestConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.rpcRequestConfigForm; + } + onConfigurationSet(configuration) { + this.rpcRequestConfigForm = this.fb.group({ + timeoutInSeconds: [configuration ? configuration.timeoutInSeconds : null, [Validators.required, Validators.min(0)]] + }); + } +} +RpcRequestConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcRequestConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RpcRequestConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RpcRequestConfigComponent, selector: "tb-action-node-rpc-request-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.timeout-sec\n \n \n {{ 'tb.rulenode.timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.min-timeout-message' | translate }}\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcRequestConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-rpc-request-config', + templateUrl: './rpc-request-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SaveToCustomTableConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.saveToCustomTableConfigForm; + } + onConfigurationSet(configuration) { + this.saveToCustomTableConfigForm = this.fb.group({ + tableName: [configuration ? configuration.tableName : null, [Validators.required, Validators.pattern(/.*\S.*/)]], + fieldsMapping: [configuration ? configuration.fieldsMapping : null, [Validators.required]] + }); + } + prepareOutputConfig(configuration) { + configuration.tableName = configuration.tableName.trim(); + return configuration; + } +} +SaveToCustomTableConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SaveToCustomTableConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SaveToCustomTableConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SaveToCustomTableConfigComponent, selector: "tb-action-node-custom-table-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.custom-table-name\n \n \n {{ 'tb.rulenode.custom-table-name-required' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SaveToCustomTableConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-custom-table-config', + templateUrl: './save-to-custom-table-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SendEmailConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.smtpProtocols = [ + 'smtp', + 'smtps' + ]; + this.tlsVersions = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3']; + } + configForm() { + return this.sendEmailConfigForm; + } + onConfigurationSet(configuration) { + this.sendEmailConfigForm = this.fb.group({ + useSystemSmtpSettings: [configuration ? configuration.useSystemSmtpSettings : false, []], + smtpProtocol: [configuration ? configuration.smtpProtocol : null, []], + smtpHost: [configuration ? configuration.smtpHost : null, []], + smtpPort: [configuration ? configuration.smtpPort : null, []], + timeout: [configuration ? configuration.timeout : null, []], + enableTls: [configuration ? configuration.enableTls : false, []], + tlsVersion: [configuration ? configuration.tlsVersion : null, []], + enableProxy: [configuration ? configuration.enableProxy : false, []], + proxyHost: [configuration ? configuration.proxyHost : null, []], + proxyPort: [configuration ? configuration.proxyPort : null, []], + proxyUser: [configuration ? configuration.proxyUser : null, []], + proxyPassword: [configuration ? configuration.proxyPassword : null, []], + username: [configuration ? configuration.username : null, []], + password: [configuration ? configuration.password : null, []] + }); + } + validatorTriggers() { + return ['useSystemSmtpSettings', 'enableProxy']; + } + updateValidators(emitEvent) { + const useSystemSmtpSettings = this.sendEmailConfigForm.get('useSystemSmtpSettings').value; + const enableProxy = this.sendEmailConfigForm.get('enableProxy').value; + if (useSystemSmtpSettings) { + this.sendEmailConfigForm.get('smtpProtocol').setValidators([]); + this.sendEmailConfigForm.get('smtpHost').setValidators([]); + this.sendEmailConfigForm.get('smtpPort').setValidators([]); + this.sendEmailConfigForm.get('timeout').setValidators([]); + this.sendEmailConfigForm.get('proxyHost').setValidators([]); + this.sendEmailConfigForm.get('proxyPort').setValidators([]); + } + else { + this.sendEmailConfigForm.get('smtpProtocol').setValidators([Validators.required]); + this.sendEmailConfigForm.get('smtpHost').setValidators([Validators.required]); + this.sendEmailConfigForm.get('smtpPort').setValidators([Validators.required, Validators.min(1), Validators.max(65535)]); + this.sendEmailConfigForm.get('timeout').setValidators([Validators.required, Validators.min(0)]); + this.sendEmailConfigForm.get('proxyHost').setValidators(enableProxy ? [Validators.required] : []); + this.sendEmailConfigForm.get('proxyPort').setValidators(enableProxy ? + [Validators.required, Validators.min(1), Validators.max(65535)] : []); + } + this.sendEmailConfigForm.get('smtpProtocol').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('smtpHost').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('smtpPort').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('timeout').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('proxyHost').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('proxyPort').updateValueAndValidity({ emitEvent }); + } +} +SendEmailConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendEmailConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SendEmailConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SendEmailConfigComponent, selector: "tb-action-node-send-email-config", usesInheritance: true, ngImport: i0, template: "
        \n \n {{ 'tb.rulenode.use-system-smtp-settings' | translate }}\n \n
        \n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
        \n \n tb.rulenode.smtp-host\n \n \n {{ 'tb.rulenode.smtp-host-required' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ 'tb.rulenode.smtp-port-required' | translate }}\n \n \n {{ 'tb.rulenode.smtp-port-range' | translate }}\n \n \n {{ 'tb.rulenode.smtp-port-range' | translate }}\n \n \n
        \n \n tb.rulenode.timeout-msec\n \n \n {{ 'tb.rulenode.timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.min-timeout-msec-message' | translate }}\n \n \n \n {{ 'tb.rulenode.enable-tls' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ 'tb.rulenode.enable-proxy' | translate }}\n \n
        \n
        \n \n tb.rulenode.proxy-host\n \n \n {{ 'tb.rulenode.proxy-host-required' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ 'tb.rulenode.proxy-port-required' | translate }}\n \n \n {{ 'tb.rulenode.proxy-port-range' | translate }}\n \n \n
        \n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
        \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
        \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$2.TbCheckboxComponent, selector: "tb-checkbox", inputs: ["disabled", "trueValue", "falseValue"], outputs: ["valueChange"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendEmailConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-send-email-config', + templateUrl: './send-email-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SendSmsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.sendSmsConfigForm; + } + onConfigurationSet(configuration) { + this.sendSmsConfigForm = this.fb.group({ + numbersToTemplate: [configuration ? configuration.numbersToTemplate : null, [Validators.required]], + smsMessageTemplate: [configuration ? configuration.smsMessageTemplate : null, [Validators.required]], + useSystemSmsSettings: [configuration ? configuration.useSystemSmsSettings : false, []], + smsProviderConfiguration: [configuration ? configuration.smsProviderConfiguration : null, []], + }); + } + validatorTriggers() { + return ['useSystemSmsSettings']; + } + updateValidators(emitEvent) { + const useSystemSmsSettings = this.sendSmsConfigForm.get('useSystemSmsSettings').value; + if (useSystemSmsSettings) { + this.sendSmsConfigForm.get('smsProviderConfiguration').setValidators([]); + } + else { + this.sendSmsConfigForm.get('smsProviderConfiguration').setValidators([Validators.required]); + } + this.sendSmsConfigForm.get('smsProviderConfiguration').updateValueAndValidity({ emitEvent }); + } +} +SendSmsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendSmsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SendSmsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SendSmsConfigComponent, selector: "tb-action-node-send-sms-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.numbers-to-template\n \n \n {{ 'tb.rulenode.numbers-to-template-required' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ 'tb.rulenode.sms-message-template-required' | translate }}\n \n \n \n \n {{ 'tb.rulenode.use-system-sms-settings' | translate }}\n \n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i5$3.SmsProviderConfigurationComponent, selector: "tb-sms-provider-configuration", inputs: ["required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendSmsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-send-sms-config', + templateUrl: './send-sms-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SnsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.snsConfigForm; + } + onConfigurationSet(configuration) { + this.snsConfigForm = this.fb.group({ + topicArnPattern: [configuration ? configuration.topicArnPattern : null, [Validators.required]], + accessKeyId: [configuration ? configuration.accessKeyId : null, [Validators.required]], + secretAccessKey: [configuration ? configuration.secretAccessKey : null, [Validators.required]], + region: [configuration ? configuration.region : null, [Validators.required]] + }); + } +} +SnsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SnsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SnsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SnsConfigComponent, selector: "tb-action-node-sns-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.topic-arn-pattern\n \n \n {{ 'tb.rulenode.topic-arn-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ 'tb.rulenode.aws-access-key-id-required' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ 'tb.rulenode.aws-secret-access-key-required' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ 'tb.rulenode.aws-region-required' | translate }}\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SnsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-sns-config', + templateUrl: './sns-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SqsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.sqsQueueType = SqsQueueType; + this.sqsQueueTypes = Object.keys(SqsQueueType); + this.sqsQueueTypeTranslationsMap = sqsQueueTypeTranslations; + } + configForm() { + return this.sqsConfigForm; + } + onConfigurationSet(configuration) { + this.sqsConfigForm = this.fb.group({ + queueType: [configuration ? configuration.queueType : null, [Validators.required]], + queueUrlPattern: [configuration ? configuration.queueUrlPattern : null, [Validators.required]], + delaySeconds: [configuration ? configuration.delaySeconds : null, [Validators.min(0), Validators.max(900)]], + messageAttributes: [configuration ? configuration.messageAttributes : null, []], + accessKeyId: [configuration ? configuration.accessKeyId : null, [Validators.required]], + secretAccessKey: [configuration ? configuration.secretAccessKey : null, [Validators.required]], + region: [configuration ? configuration.region : null, [Validators.required]] + }); + } +} +SqsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SqsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SqsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SqsConfigComponent, selector: "tb-action-node-sqs-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ 'tb.rulenode.queue-url-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ 'tb.rulenode.min-delay-seconds-message' | translate }}\n \n \n {{ 'tb.rulenode.max-delay-seconds-message' | translate }}\n \n \n \n
        \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ 'tb.rulenode.aws-access-key-id-required' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ 'tb.rulenode.aws-secret-access-key-required' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ 'tb.rulenode.aws-region-required' | translate }}\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SqsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-sqs-config', + templateUrl: './sqs-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class TimeseriesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.timeseriesConfigForm; + } + onConfigurationSet(configuration) { + this.timeseriesConfigForm = this.fb.group({ + defaultTTL: [configuration ? configuration.defaultTTL : null, [Validators.required, Validators.min(0)]] + }); + } +} +TimeseriesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TimeseriesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +TimeseriesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TimeseriesConfigComponent, selector: "tb-action-node-timeseries-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.default-ttl\n \n \n {{ 'tb.rulenode.default-ttl-required' | translate }}\n \n \n {{ 'tb.rulenode.min-default-ttl-message' | translate }}\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TimeseriesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-timeseries-config', + templateUrl: './timeseries-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class UnassignCustomerConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.unassignCustomerConfigForm; + } + onConfigurationSet(configuration) { + this.unassignCustomerConfigForm = this.fb.group({ + customerNamePattern: [configuration ? configuration.customerNamePattern : null, [Validators.required, Validators.pattern(/.*\S.*/)]], + customerCacheExpiration: [configuration ? configuration.customerCacheExpiration : null, [Validators.required, Validators.min(0)]] + }); + } + prepareOutputConfig(configuration) { + configuration.customerNamePattern = configuration.customerNamePattern.trim(); + return configuration; + } +} +UnassignCustomerConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: UnassignCustomerConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +UnassignCustomerConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: UnassignCustomerConfigComponent, selector: "tb-action-node-un-assign-to-customer-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.customer-name-pattern\n \n \n {{ 'tb.rulenode.customer-name-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ 'tb.rulenode.customer-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.customer-cache-expiration-range' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: UnassignCustomerConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-un-assign-to-customer-config', + templateUrl: './unassign-customer-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class DeviceRelationsQueryConfigComponent extends PageComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.directionTypes = Object.keys(EntitySearchDirection); + this.directionTypeTranslations = entitySearchDirectionTranslations; + this.entityType = EntityType; + this.propagateChange = null; + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + ngOnInit() { + this.deviceRelationsQueryFormGroup = this.fb.group({ + fetchLastLevelOnly: [false, []], + direction: [null, [Validators.required]], + maxLevel: [null, []], + relationType: [null], + deviceTypes: [null, [Validators.required]] + }); + this.deviceRelationsQueryFormGroup.valueChanges.subscribe((query) => { + if (this.deviceRelationsQueryFormGroup.valid) { + this.propagateChange(query); + } + else { + this.propagateChange(null); + } + }); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + setDisabledState(isDisabled) { + this.disabled = isDisabled; + if (this.disabled) { + this.deviceRelationsQueryFormGroup.disable({ emitEvent: false }); + } + else { + this.deviceRelationsQueryFormGroup.enable({ emitEvent: false }); + } + } + writeValue(query) { + this.deviceRelationsQueryFormGroup.reset(query, { emitEvent: false }); + } +} +DeviceRelationsQueryConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceRelationsQueryConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +DeviceRelationsQueryConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceRelationsQueryConfigComponent, selector: "tb-device-relations-query-config", inputs: { disabled: "disabled", required: "required" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DeviceRelationsQueryConfigComponent), + multi: true + } + ], usesInheritance: true, ngImport: i0, template: "
        \n \n {{ 'alias.last-level-relation' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-type
        \n \n \n
        device.device-types
        \n \n \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$3.RelationTypeAutocompleteComponent, selector: "tb-relation-type-autocomplete", inputs: ["required", "disabled"] }, { type: i8$2.EntitySubTypeListComponent, selector: "tb-entity-subtype-list", inputs: ["required", "disabled", "entityType"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceRelationsQueryConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-device-relations-query-config', + templateUrl: './device-relations-query-config.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DeviceRelationsQueryConfigComponent), + multi: true + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ + type: Input + }], required: [{ + type: Input + }] } }); + +class RelationsQueryConfigComponent extends PageComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.directionTypes = Object.keys(EntitySearchDirection); + this.directionTypeTranslations = entitySearchDirectionTranslations; + this.propagateChange = null; + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + ngOnInit() { + this.relationsQueryFormGroup = this.fb.group({ + fetchLastLevelOnly: [false, []], + direction: [null, [Validators.required]], + maxLevel: [null, []], + filters: [null] + }); + this.relationsQueryFormGroup.valueChanges.subscribe((query) => { + if (this.relationsQueryFormGroup.valid) { + this.propagateChange(query); + } + else { + this.propagateChange(null); + } + }); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + setDisabledState(isDisabled) { + this.disabled = isDisabled; + if (this.disabled) { + this.relationsQueryFormGroup.disable({ emitEvent: false }); + } + else { + this.relationsQueryFormGroup.enable({ emitEvent: false }); + } + } + writeValue(query) { + this.relationsQueryFormGroup.reset(query || {}, { emitEvent: false }); + } +} +RelationsQueryConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelationsQueryConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RelationsQueryConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: { disabled: "disabled", required: "required" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => RelationsQueryConfigComponent), + multi: true + } + ], usesInheritance: true, ngImport: i0, template: "
        \n \n {{ 'alias.last-level-relation' | translate }}\n \n
        \n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
        \n
        relation.relation-filters
        \n \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$4.RelationFiltersComponent, selector: "tb-relation-filters", inputs: ["disabled", "allowedEntityTypes"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelationsQueryConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-relations-query-config', + templateUrl: './relations-query-config.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => RelationsQueryConfigComponent), + multi: true + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ + type: Input + }], required: [{ + type: Input + }] } }); + +class MessageTypesConfigComponent extends PageComponent { + constructor(store, translate, truncate, fb) { + super(store); + this.store = store; + this.translate = translate; + this.truncate = truncate; + this.fb = fb; + this.placeholder = 'tb.rulenode.message-type'; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + this.messageTypes = []; + this.messageTypesList = []; + this.searchText = ''; + this.propagateChange = (v) => { }; + this.messageTypeConfigForm = this.fb.group({ + messageType: [null] + }); + for (const type of Object.keys(MessageType)) { + this.messageTypesList.push({ + name: messageTypeNames.get(MessageType[type]), + value: type + }); + } + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + ngOnInit() { + this.filteredMessageTypes = this.messageTypeConfigForm.get('messageType').valueChanges + .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchMessageTypes(name)), share()); + } + ngAfterViewInit() { } + setDisabledState(isDisabled) { + this.disabled = isDisabled; + if (this.disabled) { + this.messageTypeConfigForm.disable({ emitEvent: false }); + } + else { + this.messageTypeConfigForm.enable({ emitEvent: false }); + } + } + writeValue(value) { + this.searchText = ''; + this.messageTypes.length = 0; + if (value) { + value.forEach((type) => { + const found = this.messageTypesList.find((messageType => messageType.value === type)); + if (found) { + this.messageTypes.push({ + name: found.name, + value: found.value + }); + } + else { + this.messageTypes.push({ + name: type, + value: type + }); + } + }); + } + } + displayMessageTypeFn(messageType) { + return messageType ? messageType.name : undefined; + } + textIsNotEmpty(text) { + return (text && text != null && text.length > 0) ? true : false; + } + createMessageType($event, value) { + $event.preventDefault(); + this.transformMessageType(value); + } + add(event) { + this.transformMessageType(event.value); + } + fetchMessageTypes(searchText) { + this.searchText = searchText; + if (this.searchText && this.searchText.length) { + const search = this.searchText.toUpperCase(); + return of(this.messageTypesList.filter(messageType => messageType.name.toUpperCase().includes(search))); + } + else { + return of(this.messageTypesList); + } + } + transformMessageType(value) { + if ((value || '').trim()) { + let newMessageType = null; + const messageTypeName = value.trim(); + const existingMessageType = this.messageTypesList.find(messageType => messageType.name === messageTypeName); + if (existingMessageType) { + newMessageType = { + name: existingMessageType.name, + value: existingMessageType.value + }; + } + else { + newMessageType = { + name: messageTypeName, + value: messageTypeName + }; + } + if (newMessageType) { + this.addMessageType(newMessageType); + } + } + this.clear(''); + } + remove(messageType) { + const index = this.messageTypes.indexOf(messageType); + if (index >= 0) { + this.messageTypes.splice(index, 1); + this.updateModel(); + } + } + selected(event) { + this.addMessageType(event.option.value); + this.clear(''); + } + addMessageType(messageType) { + const index = this.messageTypes.findIndex(existingMessageType => existingMessageType.value === messageType.value); + if (index === -1) { + this.messageTypes.push(messageType); + this.updateModel(); + } + } + onFocus() { + this.messageTypeConfigForm.get('messageType').updateValueAndValidity({ onlySelf: true, emitEvent: true }); + } + clear(value = '') { + this.messageTypeInput.nativeElement.value = value; + this.messageTypeConfigForm.get('messageType').patchValue(null, { emitEvent: true }); + setTimeout(() => { + this.messageTypeInput.nativeElement.blur(); + this.messageTypeInput.nativeElement.focus(); + }, 0); + } + updateModel() { + const value = this.messageTypes.map((messageType => messageType.value)); + if (this.required) { + this.chipList.errorState = !value.length; + this.propagateChange(value.length > 0 ? value : null); + } + else { + this.chipList.errorState = false; + this.propagateChange(value); + } + } +} +MessageTypesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypesConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i3$4.TruncatePipe }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MessageTypesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MessageTypesConfigComponent, selector: "tb-message-types-config", inputs: { required: "required", label: "label", placeholder: "placeholder", disabled: "disabled" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MessageTypesConfigComponent), + multi: true + } + ], viewQueries: [{ propertyName: "chipList", first: true, predicate: ["chipList"], descendants: true }, { propertyName: "matAutocomplete", first: true, predicate: ["messageTypeAutocomplete"], descendants: true }, { propertyName: "messageTypeInput", first: true, predicate: ["messageTypeInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-message-types-found\n
        \n \n \n {{ translate.get('tb.rulenode.no-message-type-matching',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
        \n
        \n
        \n \n {{ 'tb.rulenode.message-types-required' | translate }}\n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-message-types-config', + templateUrl: './message-types-config.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MessageTypesConfigComponent), + multi: true + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i3$4.TruncatePipe }, { type: i2.FormBuilder }]; }, propDecorators: { required: [{ + type: Input + }], label: [{ + type: Input + }], placeholder: [{ + type: Input + }], disabled: [{ + type: Input + }], chipList: [{ + type: ViewChild, + args: ['chipList', { static: false }] + }], matAutocomplete: [{ + type: ViewChild, + args: ['messageTypeAutocomplete', { static: false }] + }], messageTypeInput: [{ + type: ViewChild, + args: ['messageTypeInput', { static: false }] + }] } }); + +class RulenodeCoreConfigCommonModule { +} +RulenodeCoreConfigCommonModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RulenodeCoreConfigCommonModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, declarations: [KvMapConfigComponent, + DeviceRelationsQueryConfigComponent, + RelationsQueryConfigComponent, + MessageTypesConfigComponent, + CredentialsConfigComponent, + SafeHtmlPipe], imports: [CommonModule, + SharedModule, + HomeComponentsModule], exports: [KvMapConfigComponent, + DeviceRelationsQueryConfigComponent, + RelationsQueryConfigComponent, + MessageTypesConfigComponent, + CredentialsConfigComponent, + SafeHtmlPipe] }); +RulenodeCoreConfigCommonModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, imports: [[ + CommonModule, + SharedModule, + HomeComponentsModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + KvMapConfigComponent, + DeviceRelationsQueryConfigComponent, + RelationsQueryConfigComponent, + MessageTypesConfigComponent, + CredentialsConfigComponent, + SafeHtmlPipe + ], + imports: [ + CommonModule, + SharedModule, + HomeComponentsModule + ], + exports: [ + KvMapConfigComponent, + DeviceRelationsQueryConfigComponent, + RelationsQueryConfigComponent, + MessageTypesConfigComponent, + CredentialsConfigComponent, + SafeHtmlPipe + ] + }] + }] }); + +class RuleNodeCoreConfigActionModule { +} +RuleNodeCoreConfigActionModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RuleNodeCoreConfigActionModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, declarations: [AttributesConfigComponent, + TimeseriesConfigComponent, + RpcRequestConfigComponent, + LogConfigComponent, + AssignCustomerConfigComponent, + ClearAlarmConfigComponent, + CreateAlarmConfigComponent, + CreateRelationConfigComponent, + MsgDelayConfigComponent, + DeleteRelationConfigComponent, + GeneratorConfigComponent, + GpsGeoActionConfigComponent, + MsgCountConfigComponent, + RpcReplyConfigComponent, + SaveToCustomTableConfigComponent, + UnassignCustomerConfigComponent, + SnsConfigComponent, + SqsConfigComponent, + PubSubConfigComponent, + KafkaConfigComponent, + MqttConfigComponent, + RabbitMqConfigComponent, + RestApiCallConfigComponent, + SendEmailConfigComponent, + CheckPointConfigComponent, + AzureIotHubConfigComponent, + DeviceProfileConfigComponent, + SendSmsConfigComponent, + PushToEdgeConfigComponent, + PushToCloudConfigComponent], imports: [CommonModule, + SharedModule, + HomeComponentsModule, + RulenodeCoreConfigCommonModule], exports: [AttributesConfigComponent, + TimeseriesConfigComponent, + RpcRequestConfigComponent, + LogConfigComponent, + AssignCustomerConfigComponent, + ClearAlarmConfigComponent, + CreateAlarmConfigComponent, + CreateRelationConfigComponent, + MsgDelayConfigComponent, + DeleteRelationConfigComponent, + GeneratorConfigComponent, + GpsGeoActionConfigComponent, + MsgCountConfigComponent, + RpcReplyConfigComponent, + SaveToCustomTableConfigComponent, + UnassignCustomerConfigComponent, + SnsConfigComponent, + SqsConfigComponent, + PubSubConfigComponent, + KafkaConfigComponent, + MqttConfigComponent, + RabbitMqConfigComponent, + RestApiCallConfigComponent, + SendEmailConfigComponent, + CheckPointConfigComponent, + AzureIotHubConfigComponent, + DeviceProfileConfigComponent, + SendSmsConfigComponent, + PushToEdgeConfigComponent, + PushToCloudConfigComponent] }); +RuleNodeCoreConfigActionModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, imports: [[ + CommonModule, + SharedModule, + HomeComponentsModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + AttributesConfigComponent, + TimeseriesConfigComponent, + RpcRequestConfigComponent, + LogConfigComponent, + AssignCustomerConfigComponent, + ClearAlarmConfigComponent, + CreateAlarmConfigComponent, + CreateRelationConfigComponent, + MsgDelayConfigComponent, + DeleteRelationConfigComponent, + GeneratorConfigComponent, + GpsGeoActionConfigComponent, + MsgCountConfigComponent, + RpcReplyConfigComponent, + SaveToCustomTableConfigComponent, + UnassignCustomerConfigComponent, + SnsConfigComponent, + SqsConfigComponent, + PubSubConfigComponent, + KafkaConfigComponent, + MqttConfigComponent, + RabbitMqConfigComponent, + RestApiCallConfigComponent, + SendEmailConfigComponent, + CheckPointConfigComponent, + AzureIotHubConfigComponent, + DeviceProfileConfigComponent, + SendSmsConfigComponent, + PushToEdgeConfigComponent, + PushToCloudConfigComponent + ], + imports: [ + CommonModule, + SharedModule, + HomeComponentsModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + AttributesConfigComponent, + TimeseriesConfigComponent, + RpcRequestConfigComponent, + LogConfigComponent, + AssignCustomerConfigComponent, + ClearAlarmConfigComponent, + CreateAlarmConfigComponent, + CreateRelationConfigComponent, + MsgDelayConfigComponent, + DeleteRelationConfigComponent, + GeneratorConfigComponent, + GpsGeoActionConfigComponent, + MsgCountConfigComponent, + RpcReplyConfigComponent, + SaveToCustomTableConfigComponent, + UnassignCustomerConfigComponent, + SnsConfigComponent, + SqsConfigComponent, + PubSubConfigComponent, + KafkaConfigComponent, + MqttConfigComponent, + RabbitMqConfigComponent, + RestApiCallConfigComponent, + SendEmailConfigComponent, + CheckPointConfigComponent, + AzureIotHubConfigComponent, + DeviceProfileConfigComponent, + SendSmsConfigComponent, + PushToEdgeConfigComponent, + PushToCloudConfigComponent + ] + }] + }] }); + +class CalculateDeltaConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.calculateDeltaConfigForm; + } + onConfigurationSet(configuration) { + this.calculateDeltaConfigForm = this.fb.group({ + inputValueKey: [configuration ? configuration.inputValueKey : null, [Validators.required]], + outputValueKey: [configuration ? configuration.outputValueKey : null, [Validators.required]], + useCache: [configuration ? configuration.useCache : null, []], + addPeriodBetweenMsgs: [configuration ? configuration.addPeriodBetweenMsgs : false, []], + periodValueKey: [configuration ? configuration.periodValueKey : null, []], + round: [configuration ? configuration.round : null, [Validators.min(0), Validators.max(15)]], + tellFailureIfDeltaIsNegative: [configuration ? configuration.tellFailureIfDeltaIsNegative : null, []] + }); + } + updateValidators(emitEvent) { + const addPeriodBetweenMsgs = this.calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value; + if (addPeriodBetweenMsgs) { + this.calculateDeltaConfigForm.get('periodValueKey').setValidators([Validators.required]); + } + else { + this.calculateDeltaConfigForm.get('periodValueKey').setValidators([]); + } + this.calculateDeltaConfigForm.get('periodValueKey').updateValueAndValidity({ emitEvent }); + } + validatorTriggers() { + return ['addPeriodBetweenMsgs']; + } +} +CalculateDeltaConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CalculateDeltaConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CalculateDeltaConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CalculateDeltaConfigComponent, selector: "tb-enrichment-node-calculate-delta-config", usesInheritance: true, ngImport: i0, template: "
        \n
        \n \n tb.rulenode.input-value-key\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ 'tb.rulenode.round-range' | translate }}\n \n \n {{ 'tb.rulenode.round-range' | translate }}\n \n \n
        \n \n {{ 'tb.rulenode.use-cache' | translate }}\n \n \n {{ 'tb.rulenode.tell-failure-if-delta-is-negative' | translate }}\n \n \n {{ 'tb.rulenode.add-period-between-msgs' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CalculateDeltaConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-calculate-delta-config', + templateUrl: './calculate-delta-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class CustomerAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.customerAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.customerAttributesConfigForm = this.fb.group({ + telemetry: [configuration ? configuration.telemetry : false, []], + attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] + }); + } +} +CustomerAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CustomerAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CustomerAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CustomerAttributesConfigComponent, selector: "tb-enrichment-node-customer-attributes-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CustomerAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-customer-attributes-config', + templateUrl: './customer-attributes-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class DeviceAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.deviceAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.deviceAttributesConfigForm = this.fb.group({ + deviceRelationsQuery: [configuration ? configuration.deviceRelationsQuery : null, [Validators.required]], + tellFailureIfAbsent: [configuration ? configuration.tellFailureIfAbsent : false, []], + clientAttributeNames: [configuration ? configuration.clientAttributeNames : null, []], + sharedAttributeNames: [configuration ? configuration.sharedAttributeNames : null, []], + serverAttributeNames: [configuration ? configuration.serverAttributeNames : null, []], + latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], + getLatestValueWithTs: [configuration ? configuration.getLatestValueWithTs : false, []] + }); + } + removeKey(key, keysField) { + const keys = this.deviceAttributesConfigForm.get(keysField).value; + const index = keys.indexOf(key); + if (index >= 0) { + keys.splice(index, 1); + this.deviceAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + addKey(event, keysField) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let keys = this.deviceAttributesConfigForm.get(keysField).value; + if (!keys || keys.indexOf(value) === -1) { + if (!keys) { + keys = []; + } + keys.push(value); + this.deviceAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } +} +DeviceAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +DeviceAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceAttributesConfigComponent, selector: "tb-enrichment-node-device-attributes-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n \n {{ 'tb.rulenode.tell-failure-if-absent' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ 'tb.rulenode.get-latest-value-with-ts' | translate }}\n \n
        \n
        \n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: DeviceRelationsQueryConfigComponent, selector: "tb-device-relations-query-config", inputs: ["disabled", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-device-attributes-config', + templateUrl: './device-attributes-config.component.html', + styleUrls: ['./device-attributes-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class EntityDetailsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, translate, fb) { + super(store); + this.store = store; + this.translate = translate; + this.fb = fb; + this.entityDetailsTranslationsMap = entityDetailsTranslations; + this.entityDetailsList = []; + this.searchText = ''; + this.displayDetailsFn = this.displayDetails.bind(this); + for (const field of Object.keys(EntityDetailsField)) { + this.entityDetailsList.push(EntityDetailsField[field]); + } + this.detailsFormControl = new FormControl(''); + this.filteredEntityDetails = this.detailsFormControl.valueChanges + .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchEntityDetails(name)), share()); + } + ngOnInit() { + super.ngOnInit(); + } + configForm() { + return this.entityDetailsConfigForm; + } + prepareInputConfig(configuration) { + this.searchText = ''; + this.detailsFormControl.patchValue('', { emitEvent: true }); + return configuration; + } + onConfigurationSet(configuration) { + this.entityDetailsConfigForm = this.fb.group({ + detailsList: [configuration ? configuration.detailsList : null, [Validators.required]], + addToMetadata: [configuration ? configuration.addToMetadata : false, []] + }); + } + displayDetails(details) { + return details ? this.translate.instant(entityDetailsTranslations.get(details)) : undefined; + } + fetchEntityDetails(searchText) { + this.searchText = searchText; + if (this.searchText && this.searchText.length) { + const search = this.searchText.toUpperCase(); + return of(this.entityDetailsList.filter(field => this.translate.instant(entityDetailsTranslations.get(EntityDetailsField[field])).toUpperCase().includes(search))); + } + else { + return of(this.entityDetailsList); + } + } + detailsFieldSelected(event) { + this.addDetailsField(event.option.value); + this.clear(''); + } + removeDetailsField(details) { + const detailsList = this.entityDetailsConfigForm.get('detailsList').value; + if (detailsList) { + const index = detailsList.indexOf(details); + if (index >= 0) { + detailsList.splice(index, 1); + this.entityDetailsConfigForm.get('detailsList').setValue(detailsList); + } + } + } + addDetailsField(details) { + let detailsList = this.entityDetailsConfigForm.get('detailsList').value; + if (!detailsList) { + detailsList = []; + } + const index = detailsList.indexOf(details); + if (index === -1) { + detailsList.push(details); + this.entityDetailsConfigForm.get('detailsList').setValue(detailsList); + } + } + onEntityDetailsInputFocus() { + this.detailsFormControl.updateValueAndValidity({ onlySelf: true, emitEvent: true }); + } + clear(value = '') { + this.detailsInput.nativeElement.value = value; + this.detailsFormControl.patchValue(null, { emitEvent: true }); + setTimeout(() => { + this.detailsInput.nativeElement.blur(); + this.detailsInput.nativeElement.focus(); + }, 0); + } +} +EntityDetailsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EntityDetailsConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +EntityDetailsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: EntityDetailsConfigComponent, selector: "tb-enrichment-node-entity-details-config", viewQueries: [{ propertyName: "detailsInput", first: true, predicate: ["detailsInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-entity-details-matching\n
        \n
        \n
        \n
        \n
        \n \n \n {{ 'tb.rulenode.add-to-metadata' | translate }}\n \n
        tb.rulenode.add-to-metadata-hint
        \n
        \n", styles: [":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EntityDetailsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-entity-details-config', + templateUrl: './entity-details-config.component.html', + styleUrls: ['./entity-details-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i2.FormBuilder }]; }, propDecorators: { detailsInput: [{ + type: ViewChild, + args: ['detailsInput', { static: false }] + }] } }); + +class GetTelemetryFromDatabaseConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + this.aggregationTypes = AggregationType; + this.aggregations = Object.keys(AggregationType); + this.aggregationTypesTranslations = aggregationTranslations; + this.fetchMode = FetchMode; + this.fetchModes = Object.keys(FetchMode); + this.samplingOrders = Object.keys(SamplingOrder); + this.timeUnits = Object.values(TimeUnit); + this.timeUnitsTranslationMap = timeUnitTranslations; + } + configForm() { + return this.getTelemetryFromDatabaseConfigForm; + } + onConfigurationSet(configuration) { + this.getTelemetryFromDatabaseConfigForm = this.fb.group({ + latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], + aggregation: [configuration ? configuration.aggregation : null, [Validators.required]], + fetchMode: [configuration ? configuration.fetchMode : null, [Validators.required]], + orderBy: [configuration ? configuration.orderBy : null, []], + limit: [configuration ? configuration.limit : null, []], + useMetadataIntervalPatterns: [configuration ? configuration.useMetadataIntervalPatterns : false, []], + startInterval: [configuration ? configuration.startInterval : null, []], + startIntervalTimeUnit: [configuration ? configuration.startIntervalTimeUnit : null, []], + endInterval: [configuration ? configuration.endInterval : null, []], + endIntervalTimeUnit: [configuration ? configuration.endIntervalTimeUnit : null, []], + startIntervalPattern: [configuration ? configuration.startIntervalPattern : null, []], + endIntervalPattern: [configuration ? configuration.endIntervalPattern : null, []], + }); + } + validatorTriggers() { + return ['fetchMode', 'useMetadataIntervalPatterns']; + } + updateValidators(emitEvent) { + const fetchMode = this.getTelemetryFromDatabaseConfigForm.get('fetchMode').value; + const useMetadataIntervalPatterns = this.getTelemetryFromDatabaseConfigForm.get('useMetadataIntervalPatterns').value; + if (fetchMode && fetchMode === FetchMode.ALL) { + this.getTelemetryFromDatabaseConfigForm.get('aggregation').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('orderBy').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('limit').setValidators([Validators.required, Validators.min(2), Validators.max(1000)]); + } + else { + this.getTelemetryFromDatabaseConfigForm.get('aggregation').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('orderBy').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('limit').setValidators([]); + } + if (useMetadataIntervalPatterns) { + this.getTelemetryFromDatabaseConfigForm.get('startInterval').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('endInterval').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').setValidators([Validators.required]); + } + else { + this.getTelemetryFromDatabaseConfigForm.get('startInterval').setValidators([Validators.required, + Validators.min(1), Validators.max(2147483647)]); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('endInterval').setValidators([Validators.required, + Validators.min(1), Validators.max(2147483647)]); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').setValidators([]); + } + this.getTelemetryFromDatabaseConfigForm.get('aggregation').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('orderBy').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('limit').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('startInterval').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('endInterval').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').updateValueAndValidity({ emitEvent }); + } + removeKey(key, keysField) { + const keys = this.getTelemetryFromDatabaseConfigForm.get(keysField).value; + const index = keys.indexOf(key); + if (index >= 0) { + keys.splice(index, 1); + this.getTelemetryFromDatabaseConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + addKey(event, keysField) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let keys = this.getTelemetryFromDatabaseConfigForm.get(keysField).value; + if (!keys || keys.indexOf(value) === -1) { + if (!keys) { + keys = []; + } + keys.push(value); + this.getTelemetryFromDatabaseConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } +} +GetTelemetryFromDatabaseConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GetTelemetryFromDatabaseConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +GetTelemetryFromDatabaseConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GetTelemetryFromDatabaseConfigComponent, selector: "tb-enrichment-node-get-telemetry-from-database", usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
        \n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
        \n \n {{ 'tb.rulenode.use-metadata-interval-patterns' | translate }}\n \n
        tb.rulenode.use-metadata-interval-patterns-hint
        \n
        \n
        \n \n tb.rulenode.start-interval\n \n \n {{ 'tb.rulenode.start-interval-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n tb.rulenode.end-interval\n \n \n {{ 'tb.rulenode.end-interval-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
        \n
        \n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ 'tb.rulenode.start-interval-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ 'tb.rulenode.end-interval-pattern-required' | translate }}\n \n \n \n \n
        \n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GetTelemetryFromDatabaseConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-get-telemetry-from-database', + templateUrl: './get-telemetry-from-database-config.component.html', + styleUrls: ['./get-telemetry-from-database-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class OriginatorAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.originatorAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.originatorAttributesConfigForm = this.fb.group({ + tellFailureIfAbsent: [configuration ? configuration.tellFailureIfAbsent : false, []], + clientAttributeNames: [configuration ? configuration.clientAttributeNames : null, []], + sharedAttributeNames: [configuration ? configuration.sharedAttributeNames : null, []], + serverAttributeNames: [configuration ? configuration.serverAttributeNames : null, []], + latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], + getLatestValueWithTs: [configuration ? configuration.getLatestValueWithTs : false, []] + }); + } + removeKey(key, keysField) { + const keys = this.originatorAttributesConfigForm.get(keysField).value; + const index = keys.indexOf(key); + if (index >= 0) { + keys.splice(index, 1); + this.originatorAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + addKey(event, keysField) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let keys = this.originatorAttributesConfigForm.get(keysField).value; + if (!keys || keys.indexOf(value) === -1) { + if (!keys) { + keys = []; + } + keys.push(value); + this.originatorAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } +} +OriginatorAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +OriginatorAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorAttributesConfigComponent, selector: "tb-enrichment-node-originator-attributes-config", usesInheritance: true, ngImport: i0, template: "
        \n \n {{ 'tb.rulenode.tell-failure-if-absent' | translate }}\n \n
        tb.rulenode.tell-failure-if-absent-hint
        \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ 'tb.rulenode.get-latest-value-with-ts' | translate }}\n \n
        \n
        \n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-originator-attributes-config', + templateUrl: './originator-attributes-config.component.html', + styleUrls: ['./originator-attributes-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class OriginatorFieldsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.originatorFieldsConfigForm; + } + onConfigurationSet(configuration) { + this.originatorFieldsConfigForm = this.fb.group({ + fieldsMapping: [configuration ? configuration.fieldsMapping : null, [Validators.required]] + }); + } +} +OriginatorFieldsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorFieldsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +OriginatorFieldsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorFieldsConfigComponent, selector: "tb-enrichment-node-originator-fields-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n
        \n", components: [{ type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorFieldsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-originator-fields-config', + templateUrl: './originator-fields-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RelatedAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.relatedAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.relatedAttributesConfigForm = this.fb.group({ + relationsQuery: [configuration ? configuration.relationsQuery : null, [Validators.required]], + telemetry: [configuration ? configuration.telemetry : false, []], + attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] + }); + } +} +RelatedAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelatedAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RelatedAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RelatedAttributesConfigComponent, selector: "tb-enrichment-node-related-attributes-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
        \n", components: [{ type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: ["disabled", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelatedAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-related-attributes-config', + templateUrl: './related-attributes-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class TenantAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.tenantAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.tenantAttributesConfigForm = this.fb.group({ + telemetry: [configuration ? configuration.telemetry : false, []], + attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] + }); + } +} +TenantAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TenantAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +TenantAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TenantAttributesConfigComponent, selector: "tb-enrichment-node-tenant-attributes-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TenantAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-tenant-attributes-config', + templateUrl: './tenant-attributes-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RulenodeCoreConfigEnrichmentModule { +} +RulenodeCoreConfigEnrichmentModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RulenodeCoreConfigEnrichmentModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, declarations: [CustomerAttributesConfigComponent, + EntityDetailsConfigComponent, + DeviceAttributesConfigComponent, + OriginatorAttributesConfigComponent, + OriginatorFieldsConfigComponent, + GetTelemetryFromDatabaseConfigComponent, + RelatedAttributesConfigComponent, + TenantAttributesConfigComponent, + CalculateDeltaConfigComponent], imports: [CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule], exports: [CustomerAttributesConfigComponent, + EntityDetailsConfigComponent, + DeviceAttributesConfigComponent, + OriginatorAttributesConfigComponent, + OriginatorFieldsConfigComponent, + GetTelemetryFromDatabaseConfigComponent, + RelatedAttributesConfigComponent, + TenantAttributesConfigComponent, + CalculateDeltaConfigComponent] }); +RulenodeCoreConfigEnrichmentModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, imports: [[ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + CustomerAttributesConfigComponent, + EntityDetailsConfigComponent, + DeviceAttributesConfigComponent, + OriginatorAttributesConfigComponent, + OriginatorFieldsConfigComponent, + GetTelemetryFromDatabaseConfigComponent, + RelatedAttributesConfigComponent, + TenantAttributesConfigComponent, + CalculateDeltaConfigComponent + ], + imports: [ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + CustomerAttributesConfigComponent, + EntityDetailsConfigComponent, + DeviceAttributesConfigComponent, + OriginatorAttributesConfigComponent, + OriginatorFieldsConfigComponent, + GetTelemetryFromDatabaseConfigComponent, + RelatedAttributesConfigComponent, + TenantAttributesConfigComponent, + CalculateDeltaConfigComponent + ] + }] + }] }); + +class CheckAlarmStatusComponent extends RuleNodeConfigurationComponent { + constructor(store, translate, fb) { + super(store); + this.store = store; + this.translate = translate; + this.fb = fb; + this.alarmStatusTranslationsMap = alarmStatusTranslations; + this.alarmStatusList = []; + this.searchText = ''; + this.displayStatusFn = this.displayStatus.bind(this); + for (const field of Object.keys(AlarmStatus)) { + this.alarmStatusList.push(AlarmStatus[field]); + } + this.statusFormControl = new FormControl(''); + this.filteredAlarmStatus = this.statusFormControl.valueChanges + .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchAlarmStatus(name)), share()); + } + ngOnInit() { + super.ngOnInit(); + } + configForm() { + return this.alarmStatusConfigForm; + } + prepareInputConfig(configuration) { + this.searchText = ''; + this.statusFormControl.patchValue('', { emitEvent: true }); + return configuration; + } + onConfigurationSet(configuration) { + this.alarmStatusConfigForm = this.fb.group({ + alarmStatusList: [configuration ? configuration.alarmStatusList : null, [Validators.required]], + }); + } + displayStatus(status) { + return status ? this.translate.instant(alarmStatusTranslations.get(status)) : undefined; + } + fetchAlarmStatus(searchText) { + const alarmStatusList = this.getAlarmStatusList(); + this.searchText = searchText; + if (this.searchText && this.searchText.length) { + const search = this.searchText.toUpperCase(); + return of(alarmStatusList.filter(field => this.translate.instant(alarmStatusTranslations.get(AlarmStatus[field])).toUpperCase().includes(search))); + } + else { + return of(alarmStatusList); + } + } + alarmStatusSelected(event) { + this.addAlarmStatus(event.option.value); + this.clear(''); + } + removeAlarmStatus(status) { + const alarmStatusList = this.alarmStatusConfigForm.get('alarmStatusList').value; + if (alarmStatusList) { + const index = alarmStatusList.indexOf(status); + if (index >= 0) { + alarmStatusList.splice(index, 1); + this.alarmStatusConfigForm.get('alarmStatusList').setValue(alarmStatusList); + } + } + } + addAlarmStatus(status) { + let alarmStatusList = this.alarmStatusConfigForm.get('alarmStatusList').value; + if (!alarmStatusList) { + alarmStatusList = []; + } + const index = alarmStatusList.indexOf(status); + if (index === -1) { + alarmStatusList.push(status); + this.alarmStatusConfigForm.get('alarmStatusList').setValue(alarmStatusList); + } + } + getAlarmStatusList() { + return this.alarmStatusList.filter((listItem) => { + return this.alarmStatusConfigForm.get('alarmStatusList').value.indexOf(listItem) === -1; + }); + } + onAlarmStatusInputFocus() { + this.statusFormControl.updateValueAndValidity({ onlySelf: true, emitEvent: true }); + } + clear(value = '') { + this.alarmStatusInput.nativeElement.value = value; + this.statusFormControl.patchValue(null, { emitEvent: true }); + setTimeout(() => { + this.alarmStatusInput.nativeElement.blur(); + this.alarmStatusInput.nativeElement.focus(); + }, 0); + } +} +CheckAlarmStatusComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckAlarmStatusComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CheckAlarmStatusComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckAlarmStatusComponent, selector: "tb-filter-node-check-alarm-status-config", viewQueries: [{ propertyName: "alarmStatusInput", first: true, predicate: ["alarmStatusInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
        \n
        \n tb.rulenode.no-alarm-status-matching\n
        \n
        \n
        \n
        \n
        \n \n
        \n\n\n\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckAlarmStatusComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-check-alarm-status-config', + templateUrl: './check-alarm-status.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i2.FormBuilder }]; }, propDecorators: { alarmStatusInput: [{ + type: ViewChild, + args: ['alarmStatusInput', { static: false }] + }] } }); + +class CheckMessageConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.checkMessageConfigForm; + } + onConfigurationSet(configuration) { + this.checkMessageConfigForm = this.fb.group({ + messageNames: [configuration ? configuration.messageNames : null, []], + metadataNames: [configuration ? configuration.metadataNames : null, []], + checkAllKeys: [configuration ? configuration.checkAllKeys : false, []], + }); + } + validateConfig() { + const messageNames = this.checkMessageConfigForm.get('messageNames').value; + const metadataNames = this.checkMessageConfigForm.get('metadataNames').value; + return messageNames.length > 0 || metadataNames.length > 0; + } + removeMessageName(messageName) { + const messageNames = this.checkMessageConfigForm.get('messageNames').value; + const index = messageNames.indexOf(messageName); + if (index >= 0) { + messageNames.splice(index, 1); + this.checkMessageConfigForm.get('messageNames').setValue(messageNames, { emitEvent: true }); + } + } + removeMetadataName(metadataName) { + const metadataNames = this.checkMessageConfigForm.get('metadataNames').value; + const index = metadataNames.indexOf(metadataName); + if (index >= 0) { + metadataNames.splice(index, 1); + this.checkMessageConfigForm.get('metadataNames').setValue(metadataNames, { emitEvent: true }); + } + } + addMessageName(event) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let messageNames = this.checkMessageConfigForm.get('messageNames').value; + if (!messageNames || messageNames.indexOf(value) === -1) { + if (!messageNames) { + messageNames = []; + } + messageNames.push(value); + this.checkMessageConfigForm.get('messageNames').setValue(messageNames, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } + addMetadataName(event) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let metadataNames = this.checkMessageConfigForm.get('metadataNames').value; + if (!metadataNames || metadataNames.indexOf(value) === -1) { + if (!metadataNames) { + metadataNames = []; + } + metadataNames.push(value); + this.checkMessageConfigForm.get('metadataNames').setValue(metadataNames, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } +} +CheckMessageConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckMessageConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CheckMessageConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckMessageConfigComponent, selector: "tb-filter-node-check-message-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
        tb.rulenode.separator-hint
        \n \n {{ 'tb.rulenode.check-all-keys' | translate }}\n \n
        tb.rulenode.check-all-keys-hint
        \n
        \n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckMessageConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-check-message-config', + templateUrl: './check-message-config.component.html', + styleUrls: ['./check-message-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class CheckRelationConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.entitySearchDirection = Object.keys(EntitySearchDirection); + this.entitySearchDirectionTranslationsMap = entitySearchDirectionTranslations; + } + configForm() { + return this.checkRelationConfigForm; + } + onConfigurationSet(configuration) { + this.checkRelationConfigForm = this.fb.group({ + checkForSingleEntity: [configuration ? configuration.checkForSingleEntity : false, []], + direction: [configuration ? configuration.direction : null, []], + entityType: [configuration ? configuration.entityType : null, + configuration && configuration.checkForSingleEntity ? [Validators.required] : []], + entityId: [configuration ? configuration.entityId : null, + configuration && configuration.checkForSingleEntity ? [Validators.required] : []], + relationType: [configuration ? configuration.relationType : null, [Validators.required]] + }); + } + validatorTriggers() { + return ['checkForSingleEntity']; + } + updateValidators(emitEvent) { + const checkForSingleEntity = this.checkRelationConfigForm.get('checkForSingleEntity').value; + this.checkRelationConfigForm.get('entityType').setValidators(checkForSingleEntity ? [Validators.required] : []); + this.checkRelationConfigForm.get('entityType').updateValueAndValidity({ emitEvent }); + this.checkRelationConfigForm.get('entityId').setValidators(checkForSingleEntity ? [Validators.required] : []); + this.checkRelationConfigForm.get('entityId').updateValueAndValidity({ emitEvent }); + } +} +CheckRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CheckRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckRelationConfigComponent, selector: "tb-filter-node-check-relation-config", usesInheritance: true, ngImport: i0, template: "
        \n \n {{ 'tb.rulenode.check-relation-to-specific-entity' | translate }}\n \n
        tb.rulenode.check-relation-hint
        \n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
        \n \n \n \n \n
        \n \n \n
        \n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }, { type: i8$3.EntityAutocompleteComponent, selector: "tb-entity-autocomplete", inputs: ["entityType", "entitySubtype", "excludeEntityIds", "labelText", "requiredText", "required", "disabled"], outputs: ["entityChanged"] }, { type: i7$3.RelationTypeAutocompleteComponent, selector: "tb-relation-type-autocomplete", inputs: ["required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckRelationConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-check-relation-config', + templateUrl: './check-relation-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class GpsGeoFilterConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.perimeterType = PerimeterType; + this.perimeterTypes = Object.keys(PerimeterType); + this.perimeterTypeTranslationMap = perimeterTypeTranslations; + this.rangeUnits = Object.keys(RangeUnit); + this.rangeUnitTranslationMap = rangeUnitTranslations; + } + configForm() { + return this.geoFilterConfigForm; + } + onConfigurationSet(configuration) { + this.geoFilterConfigForm = this.fb.group({ + latitudeKeyName: [configuration ? configuration.latitudeKeyName : null, [Validators.required]], + longitudeKeyName: [configuration ? configuration.longitudeKeyName : null, [Validators.required]], + fetchPerimeterInfoFromMessageMetadata: [configuration ? configuration.fetchPerimeterInfoFromMessageMetadata : false, []], + perimeterType: [configuration ? configuration.perimeterType : null, []], + centerLatitude: [configuration ? configuration.centerLatitude : null, []], + centerLongitude: [configuration ? configuration.centerLatitude : null, []], + range: [configuration ? configuration.range : null, []], + rangeUnit: [configuration ? configuration.rangeUnit : null, []], + polygonsDefinition: [configuration ? configuration.polygonsDefinition : null, []] + }); + } + validatorTriggers() { + return ['fetchPerimeterInfoFromMessageMetadata', 'perimeterType']; + } + updateValidators(emitEvent) { + const fetchPerimeterInfoFromMessageMetadata = this.geoFilterConfigForm.get('fetchPerimeterInfoFromMessageMetadata').value; + const perimeterType = this.geoFilterConfigForm.get('perimeterType').value; + if (fetchPerimeterInfoFromMessageMetadata) { + this.geoFilterConfigForm.get('perimeterType').setValidators([]); + } + else { + this.geoFilterConfigForm.get('perimeterType').setValidators([Validators.required]); + } + if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.CIRCLE) { + this.geoFilterConfigForm.get('centerLatitude').setValidators([Validators.required, + Validators.min(-90), Validators.max(90)]); + this.geoFilterConfigForm.get('centerLongitude').setValidators([Validators.required, + Validators.min(-180), Validators.max(180)]); + this.geoFilterConfigForm.get('range').setValidators([Validators.required, Validators.min(0)]); + this.geoFilterConfigForm.get('rangeUnit').setValidators([Validators.required]); + } + else { + this.geoFilterConfigForm.get('centerLatitude').setValidators([]); + this.geoFilterConfigForm.get('centerLongitude').setValidators([]); + this.geoFilterConfigForm.get('range').setValidators([]); + this.geoFilterConfigForm.get('rangeUnit').setValidators([]); + } + if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.POLYGON) { + this.geoFilterConfigForm.get('polygonsDefinition').setValidators([Validators.required]); + } + else { + this.geoFilterConfigForm.get('polygonsDefinition').setValidators([]); + } + this.geoFilterConfigForm.get('perimeterType').updateValueAndValidity({ emitEvent: false }); + this.geoFilterConfigForm.get('centerLatitude').updateValueAndValidity({ emitEvent }); + this.geoFilterConfigForm.get('centerLongitude').updateValueAndValidity({ emitEvent }); + this.geoFilterConfigForm.get('range').updateValueAndValidity({ emitEvent }); + this.geoFilterConfigForm.get('rangeUnit').updateValueAndValidity({ emitEvent }); + this.geoFilterConfigForm.get('polygonsDefinition').updateValueAndValidity({ emitEvent }); + } +} +GpsGeoFilterConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoFilterConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +GpsGeoFilterConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GpsGeoFilterConfigComponent, selector: "tb-filter-node-gps-geofencing-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.latitude-key-name\n \n \n {{ 'tb.rulenode.latitude-key-name-required' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ 'tb.rulenode.longitude-key-name-required' | translate }}\n \n \n \n {{ 'tb.rulenode.fetch-perimeter-info-from-message-metadata' | translate }}\n \n
        \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n \n tb.rulenode.circle-center-latitude\n \n \n {{ 'tb.rulenode.circle-center-latitude-required' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ 'tb.rulenode.circle-center-longitude-required' | translate }}\n \n \n
        \n
        \n \n tb.rulenode.range\n \n \n {{ 'tb.rulenode.range-required' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
        \n
        \n
        \n
        \n \n tb.rulenode.polygon-definition\n \n \n {{ 'tb.rulenode.polygon-definition-required' | translate }}\n \n \n
        \n
        \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoFilterConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-gps-geofencing-config', + templateUrl: './gps-geo-filter-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class MessageTypeConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.messageTypeConfigForm; + } + onConfigurationSet(configuration) { + this.messageTypeConfigForm = this.fb.group({ + messageTypes: [configuration ? configuration.messageTypes : null, [Validators.required]] + }); + } +} +MessageTypeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MessageTypeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MessageTypeConfigComponent, selector: "tb-filter-node-message-type-config", usesInheritance: true, ngImport: i0, template: "
        \n \n
        \n", components: [{ type: MessageTypesConfigComponent, selector: "tb-message-types-config", inputs: ["required", "label", "placeholder", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypeConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-message-type-config', + templateUrl: './message-type-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class OriginatorTypeConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.allowedEntityTypes = [ + EntityType.DEVICE, + EntityType.ASSET, + EntityType.ENTITY_VIEW, + EntityType.TENANT, + EntityType.CUSTOMER, + EntityType.USER, + EntityType.DASHBOARD, + EntityType.RULE_CHAIN, + EntityType.RULE_NODE + ]; + } + configForm() { + return this.originatorTypeConfigForm; + } + onConfigurationSet(configuration) { + this.originatorTypeConfigForm = this.fb.group({ + originatorTypes: [configuration ? configuration.originatorTypes : null, [Validators.required]] + }); + } +} +OriginatorTypeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorTypeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +OriginatorTypeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorTypeConfigComponent, selector: "tb-filter-node-originator-type-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n
        \n", styles: [":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"], components: [{ type: i3$5.EntityTypeListComponent, selector: "tb-entity-type-list", inputs: ["required", "disabled", "allowedEntityTypes", "ignoreAuthorityFilter"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorTypeConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-originator-type-config', + templateUrl: './originator-type-config.component.html', + styleUrls: ['./originator-type-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class ScriptConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.scriptConfigForm; + } + onConfigurationSet(configuration) { + this.scriptConfigForm = this.fb.group({ + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + testScript() { + const script = this.scriptConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'filter', this.translate.instant('tb.rulenode.filter'), 'Filter', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/filter_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.scriptConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +ScriptConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ScriptConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +ScriptConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ScriptConfigComponent, selector: "tb-filter-node-script-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n
        \n \n
        \n
        \n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ScriptConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-script-config', + templateUrl: './script-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class SwitchConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.switchConfigForm; + } + onConfigurationSet(configuration) { + this.switchConfigForm = this.fb.group({ + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + testScript() { + const script = this.switchConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'switch', this.translate.instant('tb.rulenode.switch'), 'Switch', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/switch_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.switchConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +SwitchConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SwitchConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +SwitchConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SwitchConfigComponent, selector: "tb-filter-node-switch-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n
        \n \n
        \n
        \n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SwitchConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-switch-config', + templateUrl: './switch-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class RuleNodeCoreConfigFilterModule { +} +RuleNodeCoreConfigFilterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RuleNodeCoreConfigFilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, declarations: [CheckMessageConfigComponent, + CheckRelationConfigComponent, + GpsGeoFilterConfigComponent, + MessageTypeConfigComponent, + OriginatorTypeConfigComponent, + ScriptConfigComponent, + SwitchConfigComponent, + CheckAlarmStatusComponent], imports: [CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule], exports: [CheckMessageConfigComponent, + CheckRelationConfigComponent, + GpsGeoFilterConfigComponent, + MessageTypeConfigComponent, + OriginatorTypeConfigComponent, + ScriptConfigComponent, + SwitchConfigComponent, + CheckAlarmStatusComponent] }); +RuleNodeCoreConfigFilterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, imports: [[ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + CheckMessageConfigComponent, + CheckRelationConfigComponent, + GpsGeoFilterConfigComponent, + MessageTypeConfigComponent, + OriginatorTypeConfigComponent, + ScriptConfigComponent, + SwitchConfigComponent, + CheckAlarmStatusComponent + ], + imports: [ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + CheckMessageConfigComponent, + CheckRelationConfigComponent, + GpsGeoFilterConfigComponent, + MessageTypeConfigComponent, + OriginatorTypeConfigComponent, + ScriptConfigComponent, + SwitchConfigComponent, + CheckAlarmStatusComponent + ] + }] + }] }); + +class ChangeOriginatorConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.originatorSource = OriginatorSource; + this.originatorSources = Object.keys(OriginatorSource); + this.originatorSourceTranslationMap = originatorSourceTranslations; + } + configForm() { + return this.changeOriginatorConfigForm; + } + onConfigurationSet(configuration) { + this.changeOriginatorConfigForm = this.fb.group({ + originatorSource: [configuration ? configuration.originatorSource : null, [Validators.required]], + relationsQuery: [configuration ? configuration.relationsQuery : null, []] + }); + } + validatorTriggers() { + return ['originatorSource']; + } + updateValidators(emitEvent) { + const originatorSource = this.changeOriginatorConfigForm.get('originatorSource').value; + if (originatorSource && originatorSource === OriginatorSource.RELATED) { + this.changeOriginatorConfigForm.get('relationsQuery').setValidators([Validators.required]); + } + else { + this.changeOriginatorConfigForm.get('relationsQuery').setValidators([]); + } + this.changeOriginatorConfigForm.get('relationsQuery').updateValueAndValidity({ emitEvent }); + } +} +ChangeOriginatorConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ChangeOriginatorConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +ChangeOriginatorConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ChangeOriginatorConfigComponent, selector: "tb-transformation-node-change-originator-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
        \n \n \n \n
        \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: ["disabled", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ChangeOriginatorConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-transformation-node-change-originator-config', + templateUrl: './change-originator-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class TransformScriptConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.scriptConfigForm; + } + onConfigurationSet(configuration) { + this.scriptConfigForm = this.fb.group({ + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + testScript() { + const script = this.scriptConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'update', this.translate.instant('tb.rulenode.transformer'), 'Transform', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/transformation_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.scriptConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +TransformScriptConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TransformScriptConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +TransformScriptConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TransformScriptConfigComponent, selector: "tb-transformation-node-script-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
        \n \n \n \n
        \n \n
        \n
        \n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TransformScriptConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-transformation-node-script-config', + templateUrl: './script-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class ToEmailConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.mailBodyTypes = [ + { name: 'tb.mail-body-type.plain-text', value: 'false' }, + { name: 'tb.mail-body-type.html', value: 'true' }, + { name: 'tb.mail-body-type.dynamic', value: 'dynamic' } + ]; + } + configForm() { + return this.toEmailConfigForm; + } + onConfigurationSet(configuration) { + this.toEmailConfigForm = this.fb.group({ + fromTemplate: [configuration ? configuration.fromTemplate : null, [Validators.required]], + toTemplate: [configuration ? configuration.toTemplate : null, [Validators.required]], + ccTemplate: [configuration ? configuration.ccTemplate : null, []], + bccTemplate: [configuration ? configuration.bccTemplate : null, []], + subjectTemplate: [configuration ? configuration.subjectTemplate : null, [Validators.required]], + mailBodyType: [configuration ? configuration.mailBodyType : null], + isHtmlTemplate: [configuration ? configuration.isHtmlTemplate : null], + bodyTemplate: [configuration ? configuration.bodyTemplate : null, [Validators.required]], + }); + this.toEmailConfigForm.get('mailBodyType').valueChanges.pipe(startWith([configuration === null || configuration === void 0 ? void 0 : configuration.subjectTemplate])).subscribe((mailBodyType) => { + if (mailBodyType === 'dynamic') { + this.toEmailConfigForm.get('isHtmlTemplate').patchValue('', { emitEvent: false }); + this.toEmailConfigForm.get('isHtmlTemplate').setValidators(Validators.required); + } + else { + this.toEmailConfigForm.get('isHtmlTemplate').clearValidators(); + } + this.toEmailConfigForm.get('isHtmlTemplate').updateValueAndValidity(); + }); + } +} +ToEmailConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ToEmailConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +ToEmailConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ToEmailConfigComponent, selector: "tb-transformation-node-to-email-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.from-template\n \n \n {{ 'tb.rulenode.from-template-required' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ 'tb.rulenode.to-template-required' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ 'tb.rulenode.subject-template-required' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ 'tb.rulenode.body-template-required' | translate }}\n \n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ToEmailConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-transformation-node-to-email-config', + templateUrl: './to-email-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RulenodeCoreConfigTransformModule { +} +RulenodeCoreConfigTransformModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RulenodeCoreConfigTransformModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, declarations: [ChangeOriginatorConfigComponent, + TransformScriptConfigComponent, + ToEmailConfigComponent], imports: [CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule], exports: [ChangeOriginatorConfigComponent, + TransformScriptConfigComponent, + ToEmailConfigComponent] }); +RulenodeCoreConfigTransformModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, imports: [[ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + ChangeOriginatorConfigComponent, + TransformScriptConfigComponent, + ToEmailConfigComponent + ], + imports: [ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + ChangeOriginatorConfigComponent, + TransformScriptConfigComponent, + ToEmailConfigComponent + ] + }] + }] }); + +function addRuleNodeCoreLocaleEnglish(translate) { + const enUS = { + tb: { + rulenode: { + 'create-entity-if-not-exists': 'Create new entity if not exists', + 'create-entity-if-not-exists-hint': 'Create a new entity set above if it does not exist.', + 'entity-name-pattern': 'Name pattern', + 'entity-name-pattern-required': 'Name pattern is required', + 'entity-type-pattern': 'Type pattern', + 'entity-type-pattern-required': 'Type pattern is required', + 'entity-cache-expiration': 'Entities cache expiration time (sec)', + 'entity-cache-expiration-hint': 'Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.', + 'entity-cache-expiration-required': 'Entities cache expiration time is required.', + 'entity-cache-expiration-range': 'Entities cache expiration time should be greater than or equal to 0.', + 'customer-name-pattern': 'Customer name pattern', + 'customer-name-pattern-required': 'Customer name pattern is required', + 'create-customer-if-not-exists': 'Create new customer if not exists', + 'customer-cache-expiration': 'Customers cache expiration time (sec)', + 'customer-cache-expiration-hint': 'Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.', + 'customer-cache-expiration-required': 'Customers cache expiration time is required.', + 'customer-cache-expiration-range': 'Customers cache expiration time should be greater than or equal to 0.', + 'start-interval': 'Start Interval', + 'end-interval': 'End Interval', + 'start-interval-time-unit': 'Start Interval Time Unit', + 'end-interval-time-unit': 'End Interval Time Unit', + 'fetch-mode': 'Fetch mode', + 'fetch-mode-hint': 'If selected fetch mode \'ALL\' you able to choose telemetry sampling order.', + 'order-by': 'Order by', + 'order-by-hint': 'Select to choose telemetry sampling order.', + limit: 'Limit', + 'limit-hint': 'Min limit value is 2, max - 1000. In case you want to fetch a single entry, ' + + 'select fetch mode \'FIRST\' or \'LAST\'.', + 'time-unit-milliseconds': 'Milliseconds', + 'time-unit-seconds': 'Seconds', + 'time-unit-minutes': 'Minutes', + 'time-unit-hours': 'Hours', + 'time-unit-days': 'Days', + 'time-value-range': 'Time value should be in a range from 1 to 2147483647.', + 'start-interval-value-required': 'Start interval value is required.', + 'end-interval-value-required': 'End interval value is required.', + filter: 'Filter', + switch: 'Switch', + 'message-type': 'Message type', + 'message-type-required': 'Message type is required.', + 'message-types-filter': 'Message types filter', + 'no-message-types-found': 'No message types found', + 'no-message-type-matching': '\'{{messageType}}\' not found.', + 'create-new-message-type': 'Create a new one!', + 'message-types-required': 'Message types are required.', + 'client-attributes': 'Client attributes', + 'shared-attributes': 'Shared attributes', + 'server-attributes': 'Server attributes', + 'notify-device': 'Notify Device', + 'notify-device-hint': 'If the message arrives from the device, we will push it back to the device by default.', + 'latest-timeseries': 'Latest timeseries', + 'timeseries-key': 'Timeseries key', + 'data-keys': 'Message data', + 'metadata-keys': 'Message metadata', + 'relations-query': 'Relations query', + 'device-relations-query': 'Device relations query', + 'max-relation-level': 'Max relation level', + 'relation-type-pattern': 'Relation type pattern', + 'relation-type-pattern-required': 'Relation type pattern is required', + 'relation-types-list': 'Relation types to propagate', + 'relation-types-list-hint': 'If Propagate relation types are not selected, ' + + 'alarms will be propagated without filtering by relation type.', + 'unlimited-level': 'Unlimited level', + 'latest-telemetry': 'Latest telemetry', + 'attr-mapping': 'Attributes mapping', + 'source-attribute': 'Source attribute', + 'source-attribute-required': 'Source attribute is required.', + 'source-telemetry': 'Source telemetry', + 'source-telemetry-required': 'Source telemetry is required.', + 'target-attribute': 'Target attribute', + 'target-attribute-required': 'Target attribute is required.', + 'attr-mapping-required': 'At least one attribute mapping should be specified.', + 'fields-mapping': 'Fields mapping', + 'fields-mapping-required': 'At least one field mapping should be specified.', + 'source-field': 'Source field', + 'source-field-required': 'Source field is required.', + 'originator-source': 'Originator source', + 'originator-customer': 'Customer', + 'originator-tenant': 'Tenant', + 'originator-related': 'Related', + 'originator-alarm-originator': 'Alarm Originator', + 'clone-message': 'Clone message', + transform: 'Transform', + 'default-ttl': 'Default TTL in seconds', + 'default-ttl-required': 'Default TTL is required.', + 'min-default-ttl-message': 'Only 0 minimum TTL is allowed.', + 'message-count': 'Message count (0 - unlimited)', + 'message-count-required': 'Message count is required.', + 'min-message-count-message': 'Only 0 minimum message count is allowed.', + 'period-seconds': 'Period in seconds', + 'period-seconds-required': 'Period is required.', + 'use-metadata-period-in-seconds-patterns': 'Use period in seconds pattern', + 'use-metadata-period-in-seconds-patterns-hint': 'If selected, rule node use period in seconds interval pattern from message metadata or data ' + + 'assuming that intervals are in the seconds.', + 'period-in-seconds-pattern': 'Period in seconds pattern', + 'period-in-seconds-pattern-required': 'Period in seconds pattern is required', + 'min-period-seconds-message': 'Only 1 second minimum period is allowed.', + originator: 'Originator', + 'message-body': 'Message body', + 'message-metadata': 'Message metadata', + generate: 'Generate', + 'test-generator-function': 'Test generator function', + generator: 'Generator', + 'test-filter-function': 'Test filter function', + 'test-switch-function': 'Test switch function', + 'test-transformer-function': 'Test transformer function', + transformer: 'Transformer', + 'alarm-create-condition': 'Alarm create condition', + 'test-condition-function': 'Test condition function', + 'alarm-clear-condition': 'Alarm clear condition', + 'alarm-details-builder': 'Alarm details builder', + 'test-details-function': 'Test details function', + 'alarm-type': 'Alarm type', + 'alarm-type-required': 'Alarm type is required.', + 'alarm-severity': 'Alarm severity', + 'alarm-severity-required': 'Alarm severity is required', + 'alarm-status-filter': 'Alarm status filter', + 'alarm-status-list-empty': 'Alarm status list is empty', + 'no-alarm-status-matching': 'No alarm status matching were found.', + propagate: 'Propagate', + condition: 'Condition', + details: 'Details', + 'to-string': 'To string', + 'test-to-string-function': 'Test to string function', + 'from-template': 'From Template', + 'from-template-required': 'From Template is required', + 'to-template': 'To Template', + 'to-template-required': 'To Template is required', + 'mail-address-list-template-hint': 'Comma separated address list, use ${metadataKey' + + '} for value from metadata, $[messageKey' + + '] for value from message body', + 'cc-template': 'Cc Template', + 'bcc-template': 'Bcc Template', + 'subject-template': 'Subject Template', + 'subject-template-required': 'Subject Template is required', + 'body-template': 'Body Template', + 'body-template-required': 'Body Template is required', + 'dynamic-mail-body-type': 'Dynamic mail body type', + 'mail-body-type': 'Mail body type', + 'request-id-metadata-attribute': 'Request Id Metadata attribute name', + 'timeout-sec': 'Timeout in seconds', + 'timeout-required': 'Timeout is required', + 'min-timeout-message': 'Only 0 minimum timeout value is allowed.', + 'endpoint-url-pattern': 'Endpoint URL pattern', + 'endpoint-url-pattern-required': 'Endpoint URL pattern is required', + 'request-method': 'Request method', + 'use-simple-client-http-factory': 'Use simple client HTTP factory', + 'ignore-request-body': 'Without request body', + 'read-timeout': 'Read timeout in millis', + 'read-timeout-hint': 'The value of 0 means an infinite timeout', + 'max-parallel-requests-count': 'Max number of parallel requests', + 'max-parallel-requests-count-hint': 'The value of 0 specifies no limit in parallel processing', + headers: 'Headers', + 'headers-hint': 'Use ${metadataKey} ' + + 'for value from metadata, $[messageKey] ' + + 'for value from message body in header/value fields', + header: 'Header', + 'header-required': 'Header is required', + value: 'Value', + 'value-required': 'Value is required', + 'topic-pattern': 'Topic pattern', + 'topic-pattern-required': 'Topic pattern is required', + topic: 'Topic', + 'topic-required': 'Topic is required', + 'bootstrap-servers': 'Bootstrap servers', + 'bootstrap-servers-required': 'Bootstrap servers value is required', + 'other-properties': 'Other properties', + key: 'Key', + 'key-required': 'Key is required', + retries: 'Automatically retry times if fails', + 'min-retries-message': 'Only 0 minimum retries is allowed.', + 'batch-size-bytes': 'Produces batch size in bytes', + 'min-batch-size-bytes-message': 'Only 0 minimum batch size is allowed.', + 'linger-ms': 'Time to buffer locally (ms)', + 'min-linger-ms-message': 'Only 0 ms minimum value is allowed.', + 'buffer-memory-bytes': 'Client buffer max size in bytes', + 'min-buffer-memory-message': 'Only 0 minimum buffer size is allowed.', + acks: 'Number of acknowledgments', + 'key-serializer': 'Key serializer', + 'key-serializer-required': 'Key serializer is required', + 'value-serializer': 'Value serializer', + 'value-serializer-required': 'Value serializer is required', + 'topic-arn-pattern': 'Topic ARN pattern', + 'topic-arn-pattern-required': 'Topic ARN pattern is required', + 'aws-access-key-id': 'AWS Access Key ID', + 'aws-access-key-id-required': 'AWS Access Key ID is required', + 'aws-secret-access-key': 'AWS Secret Access Key', + 'aws-secret-access-key-required': 'AWS Secret Access Key is required', + 'aws-region': 'AWS Region', + 'aws-region-required': 'AWS Region is required', + 'exchange-name-pattern': 'Exchange name pattern', + 'routing-key-pattern': 'Routing key pattern', + 'message-properties': 'Message properties', + host: 'Host', + 'host-required': 'Host is required', + port: 'Port', + 'port-required': 'Port is required', + 'port-range': 'Port should be in a range from 1 to 65535.', + 'virtual-host': 'Virtual host', + username: 'Username', + password: 'Password', + 'automatic-recovery': 'Automatic recovery', + 'connection-timeout-ms': 'Connection timeout (ms)', + 'min-connection-timeout-ms-message': 'Only 0 ms minimum value is allowed.', + 'handshake-timeout-ms': 'Handshake timeout (ms)', + 'min-handshake-timeout-ms-message': 'Only 0 ms minimum value is allowed.', + 'client-properties': 'Client properties', + 'queue-url-pattern': 'Queue URL pattern', + 'queue-url-pattern-required': 'Queue URL pattern is required', + 'delay-seconds': 'Delay (seconds)', + 'min-delay-seconds-message': 'Only 0 seconds minimum value is allowed.', + 'max-delay-seconds-message': 'Only 900 seconds maximum value is allowed.', + name: 'Name', + 'name-required': 'Name is required', + 'queue-type': 'Queue type', + 'sqs-queue-standard': 'Standard', + 'sqs-queue-fifo': 'FIFO', + 'gcp-project-id': 'GCP project ID', + 'gcp-project-id-required': 'GCP project ID is required', + 'gcp-service-account-key': 'GCP service account key file', + 'gcp-service-account-key-required': 'GCP service account key file is required', + 'pubsub-topic-name': 'Topic name', + 'pubsub-topic-name-required': 'Topic name is required', + 'message-attributes': 'Message attributes', + 'message-attributes-hint': 'Use ${metadataKey} ' + + 'for value from metadata, $[messageKey] ' + + 'for value from message body in name/value fields', + 'connect-timeout': 'Connection timeout (sec)', + 'connect-timeout-required': 'Connection timeout is required.', + 'connect-timeout-range': 'Connection timeout should be in a range from 1 to 200.', + 'client-id': 'Client ID', + 'client-id-hint': 'Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.' + + 'Majority of the MQTT brokers will not allow multiple connections with the same client id. ' + + 'To connect to such brokers, your mqtt client id must be unique. ' + + 'When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. ' + + 'This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.', + 'device-id': 'Device ID', + 'device-id-required': 'Device ID is required.', + 'clean-session': 'Clean session', + 'enable-ssl': 'Enable SSL', + credentials: 'Credentials', + 'credentials-type': 'Credentials type', + 'credentials-type-required': 'Credentials type is required.', + 'credentials-anonymous': 'Anonymous', + 'credentials-basic': 'Basic', + 'credentials-pem': 'PEM', + 'credentials-pem-hint': 'At least Server CA certificate file or a pair of Client certificate and Client private key files are required', + 'credentials-sas': 'Shared Access Signature', + 'sas-key': 'SAS Key', + 'sas-key-required': 'SAS Key is required.', + hostname: 'Hostname', + 'hostname-required': 'Hostname is required.', + 'azure-ca-cert': 'CA certificate file', + 'username-required': 'Username is required.', + 'password-required': 'Password is required.', + 'ca-cert': 'Server CA certificate file *', + 'private-key': 'Client private key file *', + cert: 'Client certificate file *', + 'no-file': 'No file selected.', + 'drop-file': 'Drop a file or click to select a file to upload.', + 'private-key-password': 'Private key password', + 'use-system-smtp-settings': 'Use system SMTP settings', + 'use-metadata-interval-patterns': 'Use interval patterns', + 'use-metadata-interval-patterns-hint': 'If selected, rule node use start and end interval patterns from message metadata or data ' + + 'assuming that intervals are in the milliseconds.', + 'use-message-alarm-data': 'Use message alarm data', + 'use-dynamically-change-the-severity-of-alar': 'Use dynamically change the severity of alarm', + 'check-all-keys': 'Check that all selected keys are present', + 'check-all-keys-hint': 'If selected, checks that all specified keys are present in the message data and metadata.', + 'check-relation-to-specific-entity': 'Check relation to specific entity', + 'check-relation-hint': 'Checks existence of relation to specific entity or to any entity based on direction and relation type.', + 'delete-relation-to-specific-entity': 'Delete relation to specific entity', + 'delete-relation-hint': 'Deletes relation from the originator of the incoming message to the specified ' + + 'entity or list of entities based on direction and type.', + 'remove-current-relations': 'Remove current relations', + 'remove-current-relations-hint': 'Removes current relations from the originator of the incoming message based on direction and type.', + 'change-originator-to-related-entity': 'Change originator to related entity', + 'change-originator-to-related-entity-hint': 'Used to process submitted message as a message from another entity.', + 'start-interval-pattern': 'Start interval pattern', + 'end-interval-pattern': 'End interval pattern', + 'start-interval-pattern-required': 'Start interval pattern is required', + 'end-interval-pattern-required': 'End interval pattern is required', + 'smtp-protocol': 'Protocol', + 'smtp-host': 'SMTP host', + 'smtp-host-required': 'SMTP host is required.', + 'smtp-port': 'SMTP port', + 'smtp-port-required': 'You must supply a smtp port.', + 'smtp-port-range': 'SMTP port should be in a range from 1 to 65535.', + 'timeout-msec': 'Timeout ms', + 'min-timeout-msec-message': 'Only 0 ms minimum value is allowed.', + 'enter-username': 'Enter username', + 'enter-password': 'Enter password', + 'enable-tls': 'Enable TLS', + 'tls-version': 'TLS version', + 'enable-proxy': 'Enable proxy', + 'use-system-proxy-properties': 'Use system proxy properties', + 'proxy-host': 'Proxy host', + 'proxy-host-required': 'Proxy host is required.', + 'proxy-port': 'Proxy port', + 'proxy-port-required': 'Proxy port is required.', + 'proxy-port-range': 'Proxy port should be in a range from 1 to 65535.', + 'proxy-user': 'Proxy user', + 'proxy-password': 'Proxy password', + 'proxy-scheme': 'Proxy scheme', + 'numbers-to-template': 'Phone Numbers To Template', + 'numbers-to-template-required': 'Phone Numbers To Template is required', + 'numbers-to-template-hint': 'Comma separated Phone Numbers, use ${' + + 'metadataKey} for value from metadata, ' + + '$[messageKey] for value from message body', + 'sms-message-template': 'SMS message Template', + 'sms-message-template-required': 'SMS message Template is required', + 'use-system-sms-settings': 'Use system SMS provider settings', + 'min-period-0-seconds-message': 'Only 0 second minimum period is allowed.', + 'max-pending-messages': 'Maximum pending messages', + 'max-pending-messages-required': 'Maximum pending messages is required.', + 'max-pending-messages-range': 'Maximum pending messages should be in a range from 1 to 100000.', + 'originator-types-filter': 'Originator types filter', + 'interval-seconds': 'Interval in seconds', + 'interval-seconds-required': 'Interval is required.', + 'min-interval-seconds-message': 'Only 1 second minimum interval is allowed.', + 'output-timeseries-key-prefix': 'Output timeseries key prefix', + 'output-timeseries-key-prefix-required': 'Output timeseries key prefix required.', + 'separator-hint': 'You should press "enter" to complete field input.', + 'entity-details': 'Select entity details:', + 'entity-details-title': 'Title', + 'entity-details-country': 'Country', + 'entity-details-state': 'State', + 'entity-details-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', + 'add-metadata-key-values-as-kafka-headers': 'Add Message metadata key-value pairs to Kafka record headers', + 'add-metadata-key-values-as-kafka-headers-hint': 'If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.', + 'charset-encoding': 'Charset encoding', + 'charset-encoding-required': 'Charset encoding is required.', + 'charset-us-ascii': 'US-ASCII', + 'charset-iso-8859-1': 'ISO-8859-1', + 'charset-utf-8': 'UTF-8', + 'charset-utf-16be': 'UTF-16BE', + 'charset-utf-16le': 'UTF-16LE', + 'charset-utf-16': 'UTF-16', + 'select-queue-hint': 'The queue name can be selected from a drop-down list or add a custom name.', + 'persist-alarm-rules': 'Persist state of alarm rules', + 'fetch-alarm-rules': 'Fetch state of alarm rules', + 'input-value-key': 'Input value key', + 'input-value-key-required': 'Input value key is required.', + 'output-value-key': 'Output value key', + 'output-value-key-required': 'Output value key is required.', + round: 'Decimals', + 'round-range': 'Decimals should be in a range from 0 to 15.', + 'use-cache': 'Use cache for latest value', + 'tell-failure-if-delta-is-negative': 'Tell Failure if delta is negative', + 'add-period-between-msgs': 'Add period between messages', + 'period-value-key': 'Period value key', + 'period-key-required': 'Period value key is required.', + 'general-pattern-hint': 'Hint: use ${metadataKey} ' + + 'for value from metadata, $[messageKey] ' + + 'for value from message body', + 'alarm-severity-pattern-hint': 'Hint: use ${metadataKey} ' + + 'for value from metadata, $[messageKey] ' + + 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)' + }, + 'key-val': { + key: 'Key', + value: 'Value', + 'remove-entry': 'Remove entry', + 'add-entry': 'Add entry' + }, + 'mail-body-type': { + 'plain-text': 'Plain Text', + html: 'HTML', + dynamic: 'Dynamic' + } + } + }; + translate.setTranslation('en_US', enUS, true); +} + +class RuleNodeCoreConfigModule { + constructor(translate) { + addRuleNodeCoreLocaleEnglish(translate); + } +} +RuleNodeCoreConfigModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, deps: [{ token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.NgModule }); +RuleNodeCoreConfigModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, declarations: [EmptyConfigComponent], imports: [CommonModule, + SharedModule], exports: [RuleNodeCoreConfigActionModule, + RuleNodeCoreConfigFilterModule, + RulenodeCoreConfigEnrichmentModule, + RulenodeCoreConfigTransformModule, + EmptyConfigComponent] }); +RuleNodeCoreConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, imports: [[ + CommonModule, + SharedModule + ], RuleNodeCoreConfigActionModule, + RuleNodeCoreConfigFilterModule, + RulenodeCoreConfigEnrichmentModule, + RulenodeCoreConfigTransformModule] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + EmptyConfigComponent + ], + imports: [ + CommonModule, + SharedModule + ], + exports: [ + RuleNodeCoreConfigActionModule, + RuleNodeCoreConfigFilterModule, + RulenodeCoreConfigEnrichmentModule, + RulenodeCoreConfigTransformModule, + EmptyConfigComponent + ] + }] + }], ctorParameters: function () { return [{ type: i4.TranslateService }]; } }); + +/* + * Public API Surface of rule-core-config + */ + +/** + * Generated bundle index. Do not edit. + */ + +export { AssignCustomerConfigComponent, AttributesConfigComponent, AzureIotHubConfigComponent, CalculateDeltaConfigComponent, ChangeOriginatorConfigComponent, CheckAlarmStatusComponent, CheckMessageConfigComponent, CheckPointConfigComponent, CheckRelationConfigComponent, ClearAlarmConfigComponent, CreateAlarmConfigComponent, CreateRelationConfigComponent, CredentialsConfigComponent, CustomerAttributesConfigComponent, DeleteRelationConfigComponent, DeviceAttributesConfigComponent, DeviceProfileConfigComponent, DeviceRelationsQueryConfigComponent, EmptyConfigComponent, EntityDetailsConfigComponent, GeneratorConfigComponent, GetTelemetryFromDatabaseConfigComponent, GpsGeoActionConfigComponent, GpsGeoFilterConfigComponent, KafkaConfigComponent, KvMapConfigComponent, LogConfigComponent, MessageTypeConfigComponent, MessageTypesConfigComponent, MqttConfigComponent, MsgCountConfigComponent, MsgDelayConfigComponent, OriginatorAttributesConfigComponent, OriginatorFieldsConfigComponent, OriginatorTypeConfigComponent, PubSubConfigComponent, PushToCloudConfigComponent, PushToEdgeConfigComponent, RabbitMqConfigComponent, RelatedAttributesConfigComponent, RelationsQueryConfigComponent, RestApiCallConfigComponent, RpcReplyConfigComponent, RpcRequestConfigComponent, RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RuleNodeCoreConfigModule, RulenodeCoreConfigCommonModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, SafeHtmlPipe, SaveToCustomTableConfigComponent, ScriptConfigComponent, SendEmailConfigComponent, SendSmsConfigComponent, SnsConfigComponent, SqsConfigComponent, SwitchConfigComponent, TenantAttributesConfigComponent, TimeseriesConfigComponent, ToEmailConfigComponent, TransformScriptConfigComponent, UnassignCustomerConfigComponent }; +//# sourceMappingURL=rulenode-core-config.js.map diff --git a/ui-ngx/.browserslistrc b/ui-ngx/.browserslistrc new file mode 100644 index 0000000000..4f9ac26980 --- /dev/null +++ b/ui-ngx/.browserslistrc @@ -0,0 +1,16 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# For the full list of supported browsers by the Angular framework, please see: +# https://angular.io/guide/browser-support + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +last 1 Chrome version +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major versions +last 2 iOS major versions +Firefox ESR diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 0d6203c88e..7565ae770c 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -11,6 +11,9 @@ "schematics": { "@schematics/angular:component": { "style": "scss" + }, + "@schematics/angular:application": { + "strict": true } }, "architect": { @@ -92,6 +95,7 @@ "node_modules/tinycolor2/dist/tinycolor-min.js", "node_modules/split.js/dist/split.min.js", "node_modules/systemjs/dist/system.js", + "node_modules/systemjs-babel/dist/systemjs-babel.js", "node_modules/marked/lib/marked.js", "node_modules/prismjs/prism.js", "node_modules/prismjs/components/prism-css.min.js", @@ -99,7 +103,7 @@ "node_modules/prismjs/components/prism-json.min.js", "node_modules/prismjs/components/prism-javascript.min.js", "node_modules/prismjs/components/prism-typescript.min.js", - "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js" + "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.min.js" ], "customWebpackConfig": { "path": "./extra-webpack.config.js" @@ -130,7 +134,9 @@ "jquery.terminal", "tooltipster", "jstree", - "qrcode" + "qrcode", + "wcwidth", + "leaflet-polylinedecorator" ] }, "configurations": { @@ -141,7 +147,14 @@ "with": "src/environments/environment.prod.ts" } ], - "optimization": true, + "optimization": { + "scripts": true, + "styles": { + "minify": true, + "inlineCritical": false + }, + "fonts": false + }, "outputHashing": "all", "sourceMap": false, "namedChunks": false, @@ -155,6 +168,21 @@ "maximumError": "12mb" } ] + }, + "development": { + "buildOptimizer": false, + "optimization": { + "scripts": false, + "styles": { + "minify": false, + "inlineCritical": false + }, + "fonts": false + }, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true } } }, @@ -167,8 +195,12 @@ "configurations": { "production": { "browserTarget": "thingsboard:build:production" + }, + "development": { + "browserTarget": "thingsboard:build:development" } - } + }, + "defaultConfiguration": "development" }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", diff --git a/ui-ngx/extra-webpack.config.js b/ui-ngx/extra-webpack.config.js index ef2e115252..e1efad5e67 100644 --- a/ui-ngx/extra-webpack.config.js +++ b/ui-ngx/extra-webpack.config.js @@ -14,7 +14,7 @@ * limitations under the License. */ const CompressionPlugin = require("compression-webpack-plugin"); -const TerserPlugin = require("terser-webpack-plugin"); +const JavaScriptOptimizerPlugin = require("@angular-devkit/build-angular/src/webpack/plugins/javascript-optimizer-plugin").JavaScriptOptimizerPlugin; const webpack = require("webpack"); const dirTree = require("directory-tree"); const ngWebpack = require('@ngtools/webpack'); @@ -52,7 +52,10 @@ module.exports = (config, options) => { }) ); config.plugins.push( - new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) + new webpack.IgnorePlugin({ + resourceRegExp: /^\.\/locale$/, + contextRegExp: /moment$/, + }) ); if (config.mode === 'production') { @@ -62,11 +65,10 @@ module.exports = (config, options) => { angularCompilerOptions.emitNgModuleScope = true; config.plugins.splice(index, 1); config.plugins.push(new ngWebpack.ivy.AngularWebpackPlugin(angularCompilerOptions)); - const terserPluginOptions = config.optimization.minimizer[1].options; - delete terserPluginOptions.terserOptions.compress.global_defs.ngJitMode; - terserPluginOptions.terserOptions.compress.side_effects = false; + const javascriptOptimizerOptions = config.optimization.minimizer[1].options; + delete javascriptOptimizerOptions.define.ngJitMode; config.optimization.minimizer.splice(1, 1); - config.optimization.minimizer.push(new TerserPlugin(terserPluginOptions)); + config.optimization.minimizer.push(new JavaScriptOptimizerPlugin(javascriptOptimizerOptions)); } return config; }; diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 44cfd99ff5..1256edc46c 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -3,7 +3,7 @@ "version": "3.3.3", "scripts": { "ng": "ng", - "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", + "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", "build": "ng build", "build:prod": "ng build --configuration production --vendor-chunk", "test": "ng test", @@ -25,13 +25,13 @@ "@angular/platform-browser-dynamic": "^12.2.13", "@angular/router": "^12.2.13", "@auth0/angular-jwt": "^5.0.2", - "@date-io/date-fns": "^2.10.11", + "@date-io/date-fns": "^2.11.0", "@flowjs/flow.js": "^2.14.1", "@flowjs/ngx-flow": "~0.4.6", "@geoman-io/leaflet-geoman-free": "^2.11.3", "@juggle/resize-observer": "^3.3.1", "@mat-datetimepicker/core": "~7.0.1", - "@material-ui/core": "^4.11.4", + "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@material-ui/pickers": "^3.3.10", "@ngrx/effects": "^12.5.1", @@ -39,24 +39,23 @@ "@ngrx/store-devtools": "^12.5.1", "@ngx-translate/core": "^13.0.0", "@ngx-translate/http-loader": "^6.0.0", - "ace-builds": "^1.4.12", - "angular-gridster2": "~11.2.0", + "ace-builds": "^1.4.13", + "angular-gridster2": "~12.1.1", "angular2-hotkeys": "^2.4.0", "canvas-gauges": "^2.1.7", - "compass-sass-mixins": "^0.12.7", - "core-js": "^3.18.3", - "date-fns": "^2.21.3", + "core-js": "^3.19.2", + "date-fns": "^2.26.0", "flot": "git://github.com/thingsboard/flot.git#0.9-work", "flot.curvedlines": "git://github.com/MichaelZinsmaier/CurvedLines.git#master", "font-awesome": "^4.7.0", - "html2canvas": "^1.0.0-rc.7", - "jquery": "^3.5.1", - "jquery.terminal": "^2.24.0", - "js-beautify": "^1.13.13", + "html2canvas": "^1.3.3", + "jquery": "^3.6.0", + "jquery.terminal": "^2.29.4", + "js-beautify": "^1.14.0", "json-schema-defaults": "^0.4.0", - "jstree": "^3.3.11", + "jstree": "^3.3.12", "jstree-bootstrap-theme": "^1.0.1", - "jszip": "^3.6.0", + "jszip": "^3.7.1", "leaflet": "^1.7.1", "leaflet-polylinedecorator": "^1.6.0", "leaflet-providers": "^1.13.0", @@ -65,82 +64,85 @@ "material-design-icons": "^3.0.1", "messageformat": "^2.3.0", "moment": "^2.29.1", - "moment-timezone": "^0.5.33", - "mousetrap": "1.6.3", - "ngx-clipboard": "^14.0.1", + "moment-timezone": "^0.5.34", + "ngx-clipboard": "^14.0.2", "ngx-color-picker": "^11.0.0", - "ngx-daterangepicker-material": "^4.0.1", + "ngx-daterangepicker-material": "^5.0.1", "ngx-drag-drop": "^2.0.0", "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master", - "ngx-hm-carousel": "^2.0.0-rc.1", - "ngx-markdown": "^11.1.3", - "ngx-sharebuttons": "^8.0.5", - "ngx-translate-messageformat-compiler": "^4.9.0", + "ngx-hm-carousel": "^2.0.1", + "ngx-markdown": "^12.0.1", + "ngx-sharebuttons": "^9.0.0", + "ngx-translate-messageformat-compiler": "^4.11.0", "objectpath": "^2.0.0", - "prettier": "^2.1.2", + "prettier": "^2.5.0", "prop-types": "^15.7.2", - "qrcode": "^1.4.4", + "qrcode": "^1.5.0", "raphael": "^2.3.0", - "rc-select": "~10.5.1", - "react": "~16.14.0", - "react-ace": "^9.1.4", - "react-dom": "^16.13.1", - "react-dropzone": "^11.2.0", + "rc-select": "~13.2.0", + "react": "~17.0.2", + "react-ace": "^9.5.0", + "react-dom": "^17.0.2", + "react-dropzone": "^11.4.2", "reactcss": "^1.2.3", "rxjs": "~6.6.7", "schema-inspector": "^2.0.1", - "screenfull": "^5.1.0", + "screenfull": "^6.0.0", "split.js": "^1.6.4", - "systemjs": "0.21.5", + "systemjs": "6.11.0", + "systemjs-babel": "^0.3.1", "tinycolor2": "^1.4.2", "tooltipster": "^4.2.8", - "tslib": "^2.2.0", + "tslib": "^2.3.1", "tv4": "^1.3.0", "typeface-roboto": "^1.1.13", "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-builders/custom-webpack": "~11.1.1", + "@angular-builders/custom-webpack": "~12.1.3", "@angular-devkit/build-angular": "^12.2.13", "@angular/cli": "^12.2.13", "@angular/compiler-cli": "^12.2.13", "@angular/language-service": "^12.2.13", "@ngtools/webpack": "~12.2.13", - "@types/canvas-gauges": "^2.1.2", - "@types/flot": "^0.0.31", - "@types/jasmine": "~3.7.4", - "@types/jasminewd2": "^2.0.9", - "@types/jquery": "^3.5.2", - "@types/js-beautify": "^1.13.1", - "@types/jstree": "^3.3.40", + "@types/canvas-gauges": "^2.1.4", + "@types/flot": "^0.0.32", + "@types/jasmine": "~3.10.2", + "@types/jasminewd2": "^2.0.10", + "@types/jquery": "^3.5.9", + "@types/js-beautify": "^1.13.3", + "@types/jstree": "^3.3.41", "@types/leaflet": "^1.7.6", "@types/leaflet-polylinedecorator": "^1.6.1", "@types/leaflet-providers": "^1.2.1", "@types/leaflet.gridlayer.googlemutant": "^0.4.6", "@types/leaflet.markercluster": "^1.4.6", - "@types/lodash": "^4.14.170", + "@types/lodash": "^4.14.177", "@types/moment-timezone": "^0.5.30", - "@types/mousetrap": "1.6.3", - "@types/raphael": "^2.3.1", - "@types/react": "^16.9.51", - "@types/react-dom": "^16.9.8", - "@types/tinycolor2": "^1.4.2", - "@types/tooltipster": "^0.0.30", + "@types/mousetrap": "^1.6.0", + "@types/node": "~15.14.9", + "@types/raphael": "^2.3.2", + "@types/react": "^17.0.37", + "@types/react-dom": "^17.0.11", + "@types/systemjs": "6.1.1", + "@types/tinycolor2": "^1.4.3", + "@types/tooltipster": "^0.0.31", "codelyzer": "^6.0.2", - "compression-webpack-plugin": "^6.1.1", - "directory-tree": "^2.2.4", - "jasmine-core": "~3.7.1", + "compression-webpack-plugin": "^9.0.1", + "directory-tree": "^3.0.1", + "jasmine-core": "~3.10.1", "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.3.2", + "karma": "~6.3.9", "karma-chrome-launcher": "~3.1.0", "karma-coverage-istanbul-reporter": "~3.0.3", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", + "karma-jasmine": "~4.0.1", + "karma-jasmine-html-reporter": "^1.7.0", "ngrx-store-freeze": "^0.2.4", "patch-package": "^6.4.7", "postinstall-prepare": "^2.0.0", "protractor": "~7.0.0", - "ts-node": "^9.0.0", + "raw-loader": "^4.0.2", + "ts-node": "^10.4.0", "tslint": "~6.1.3", "typescript": "~4.3.5", "webpack": "^5.64.4" @@ -148,4 +150,4 @@ "resolutions": { "lodash": "~4.17.21" } -} \ No newline at end of file +} diff --git a/ui-ngx/src/.browserslistrc b/ui-ngx/src/.browserslistrc deleted file mode 100644 index 6ef5d1aee4..0000000000 --- a/ui-ngx/src/.browserslistrc +++ /dev/null @@ -1,10 +0,0 @@ -# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers -# For additional information regarding the format and rule options, please see: -# https://github.com/browserslist/browserslist#queries -# -# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed - -> 0.5% -last 2 versions -Firefox ESR -not dead diff --git a/ui-ngx/src/app/core/http/rule-chain.service.ts b/ui-ngx/src/app/core/http/rule-chain.service.ts index e65e7017e0..0e11c51fcb 100644 --- a/ui-ngx/src/app/core/http/rule-chain.service.ts +++ b/ui-ngx/src/app/core/http/rule-chain.service.ts @@ -45,6 +45,7 @@ import { EntityType } from '@shared/models/entity-type.models'; import { deepClone, snakeCase } from '@core/utils'; import { DebugRuleNodeEventBody } from '@app/shared/models/event.models'; import { Edge } from '@shared/models/edge.models'; +import { IModulesMap } from '@modules/common/modules-map.models'; @Injectable({ providedIn: 'root' @@ -119,14 +120,14 @@ export class RuleChainService { ); } - public getRuleNodeComponents(ruleNodeConfigResourcesModulesMap: {[key: string]: any}, ruleChainType: RuleChainType, config?: RequestConfig): + public getRuleNodeComponents(modulesMap: IModulesMap, ruleChainType: RuleChainType, config?: RequestConfig): Observable> { if (this.ruleNodeComponentsMap.get(ruleChainType)) { return of(this.ruleNodeComponentsMap.get(ruleChainType)); } else { return this.loadRuleNodeComponents(ruleChainType, config).pipe( mergeMap((components) => { - return this.resolveRuleNodeComponentsUiResources(components, ruleNodeConfigResourcesModulesMap).pipe( + return this.resolveRuleNodeComponentsUiResources(components, modulesMap).pipe( map((ruleNodeComponents) => { this.ruleNodeComponentsMap.set(ruleChainType, ruleNodeComponents); this.ruleNodeComponentsMap.get(ruleChainType).push(ruleChainNodeComponent); @@ -220,11 +221,11 @@ export class RuleChainService { } private resolveRuleNodeComponentsUiResources(components: Array, - ruleNodeConfigResourcesModulesMap: {[key: string]: any}): + modulesMap: IModulesMap): Observable> { const tasks: Observable[] = []; components.forEach((component) => { - tasks.push(this.resolveRuleNodeComponentUiResources(component, ruleNodeConfigResourcesModulesMap)); + tasks.push(this.resolveRuleNodeComponentUiResources(component, modulesMap)); }); return forkJoin(tasks).pipe( catchError((err) => { @@ -234,7 +235,7 @@ export class RuleChainService { } private resolveRuleNodeComponentUiResources(component: RuleNodeComponentDescriptor, - ruleNodeConfigResourcesModulesMap: {[key: string]: any}): + modulesMap: IModulesMap): Observable { const nodeDefinition = component.configurationDescriptor.nodeDefinition; const uiResources = nodeDefinition.uiResources; @@ -248,7 +249,7 @@ export class RuleChainService { }); } if (moduleResource) { - tasks.push(this.resourcesService.loadFactories(moduleResource, ruleNodeConfigResourcesModulesMap).pipe( + tasks.push(this.resourcesService.loadFactories(moduleResource, modulesMap).pipe( map((res) => { if (nodeDefinition.configDirective && nodeDefinition.configDirective.length) { const selector = snakeCase(nodeDefinition.configDirective, '-'); diff --git a/ui-ngx/src/app/core/services/resources.service.ts b/ui-ngx/src/app/core/services/resources.service.ts index e87f16d885..f6cd757bbb 100644 --- a/ui-ngx/src/app/core/services/resources.service.ts +++ b/ui-ngx/src/app/core/services/resources.service.ts @@ -26,8 +26,9 @@ import { import { DOCUMENT } from '@angular/common'; import { forkJoin, Observable, ReplaySubject, throwError } from 'rxjs'; import { HttpClient } from '@angular/common/http'; +import { IModulesMap } from '@modules/common/modules-map.models'; -declare const SystemJS; +declare const System; @Injectable({ providedIn: 'root' @@ -63,23 +64,19 @@ export class ResourcesService { return this.loadResourceByType(fileType, url); } - public loadFactories(url: string, modulesMap: {[key: string]: any}): Observable[]> { + public loadFactories(url: string, modulesMap: IModulesMap): Observable[]> { if (this.loadedFactories[url]) { return this.loadedFactories[url].asObservable(); } + modulesMap.init(); const subject = new ReplaySubject[]>(); this.loadedFactories[url] = subject; - if (modulesMap) { - for (const moduleId of Object.keys(modulesMap)) { - SystemJS.set(moduleId, modulesMap[moduleId]); - } - } - SystemJS.import(url).then( - (module) => { - const modules = this.extractNgModules(module); - if (modules.length) { - import('@angular/compiler').then( - () => { + import('@angular/compiler').then( + () => { + System.import(url).then( + (module) => { + const modules = this.extractNgModules(module); + if (modules.length) { const tasks: Promise>[] = []; for (const m of modules) { tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m)); @@ -101,44 +98,41 @@ export class ResourcesService { (e) => { this.loadedFactories[url].error(new Error(`Unable to compile module from url: ${url}`)); delete this.loadedFactories[url]; - }); } - ); - } else { - this.loadedFactories[url].error(new Error(`Module '${url}' doesn't have default export!`)); - delete this.loadedFactories[url]; - } - }, - (e) => { - this.loadedFactories[url].error(new Error(`Unable to load module from url: ${url}`)); - delete this.loadedFactories[url]; + }); + } else { + this.loadedFactories[url].error(new Error(`Module '${url}' doesn't have default export!`)); + delete this.loadedFactories[url]; + } + }, + (e) => { + this.loadedFactories[url].error(new Error(`Unable to load module from url: ${url}`)); + delete this.loadedFactories[url]; + } + ); } ); return subject.asObservable(); } - public loadModules(url: string, modulesMap: {[key: string]: any}): Observable[]> { + public loadModules(url: string, modulesMap: IModulesMap): Observable[]> { if (this.loadedModules[url]) { return this.loadedModules[url].asObservable(); } + modulesMap.init(); const subject = new ReplaySubject[]>(); this.loadedModules[url] = subject; - if (modulesMap) { - for (const moduleId of Object.keys(modulesMap)) { - SystemJS.set(moduleId, modulesMap[moduleId]); - } - } - SystemJS.import(url).then( - (module) => { - try { - let modules; - try { - modules = this.extractNgModules(module); - } catch (e) { - console.error(e); - } - if (modules && modules.length) { - import('@angular/compiler').then( - () => { + import('@angular/compiler').then( + () => { + System.import(url).then( + (module) => { + try { + let modules; + try { + modules = this.extractNgModules(module); + } catch (e) { + console.error(e); + } + if (modules && modules.length) { const tasks: Promise>[] = []; for (const m of modules) { tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m)); @@ -159,21 +153,21 @@ export class ResourcesService { this.loadedModules[url].error(new Error(`Unable to compile module from url: ${url}`)); delete this.loadedModules[url]; }); + } else { + this.loadedModules[url].error(new Error(`Module '${url}' doesn't have default export or not NgModule!`)); + delete this.loadedModules[url]; } - ); - } else { - this.loadedModules[url].error(new Error(`Module '${url}' doesn't have default export or not NgModule!`)); + } catch (e) { + this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); + delete this.loadedModules[url]; + } + }, + (e) => { + this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); delete this.loadedModules[url]; + console.error(`Unable to load module from url: ${url}`, e); } - } catch (e) { - this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); - delete this.loadedModules[url]; - } - }, - (e) => { - this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); - delete this.loadedModules[url]; - console.error(`Unable to load module from url: ${url}`, e); + ); } ); return subject.asObservable(); @@ -184,24 +178,23 @@ export class ResourcesService { let potentialModules = [module]; let currentScanDepth = 0; - while(potentialModules.length && currentScanDepth < 10) { - let newPotentialModules = []; - for (const module of potentialModules) { - if (module && 'ɵmod' in module) { - modules.push(module); + while (potentialModules.length && currentScanDepth < 10) { + const newPotentialModules = []; + for (const potentialModule of potentialModules) { + if (potentialModule && ('ɵmod' in potentialModule)) { + modules.push(potentialModule); } else { - for (const k of Object.keys(module)) { - if(!this.isPrimitive(module[k])) { - newPotentialModules.push(module[k]); + for (const k of Object.keys(potentialModule)) { + if (!this.isPrimitive(potentialModule[k])) { + newPotentialModules.push(potentialModule[k]); } } } } - potentialModules = newPotentialModules; currentScanDepth++; } - } catch(e) { + } catch (e) { console.log('Could not load NgModule', e); } return modules; diff --git a/ui-ngx/src/app/modules/common/modules-map.models.ts b/ui-ngx/src/app/modules/common/modules-map.models.ts new file mode 100644 index 0000000000..436890554e --- /dev/null +++ b/ui-ngx/src/app/modules/common/modules-map.models.ts @@ -0,0 +1,19 @@ +/// +/// Copyright © 2016-2021 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. +/// + +export interface IModulesMap { + init(): void; +} diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index dcb4289934..8404a03aa0 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -19,6 +19,9 @@ import * as AngularCore from '@angular/core'; import * as AngularCommon from '@angular/common'; import * as AngularForms from '@angular/forms'; import * as AngularFlexLayout from '@angular/flex-layout'; +import * as AngularFlexLayoutFlex from '@angular/flex-layout/flex'; +import * as AngularFlexLayoutGrid from '@angular/flex-layout/grid'; +import * as AngularFlexLayoutExtended from '@angular/flex-layout/extended'; import * as AngularPlatformBrowser from '@angular/platform-browser'; import * as AngularRouter from '@angular/router'; import * as AngularCdkCoercion from '@angular/cdk/coercion'; @@ -62,76 +65,520 @@ import * as AngularMaterialTabs from '@angular/material/tabs'; import * as AngularMaterialToolbar from '@angular/material/toolbar'; import * as AngularMaterialTooltip from '@angular/material/tooltip'; import * as AngularMaterialTree from '@angular/material/tree'; +import * as DragDropModule from '@angular/cdk/drag-drop'; +import * as HttpClientModule from '@angular/common/http'; + import * as NgrxStore from '@ngrx/store'; import * as RxJs from 'rxjs'; import * as RxJsOperators from 'rxjs/operators'; import * as TranslateCore from '@ngx-translate/core'; +import * as _moment from 'moment'; + import * as TbCore from '@core/public-api'; import * as TbShared from '@shared/public-api'; import * as TbHomeComponents from '@home/components/public-api'; -import * as _moment from 'moment'; -import * as DragDropModule from "@angular/cdk/drag-drop"; -import * as HttpClientModule from "@angular/common/http"; - -declare const SystemJS; - -export const modulesMap: {[key: string]: any} = { - '@angular/animations': SystemJS.newModule(AngularAnimations), - '@angular/core': SystemJS.newModule(AngularCore), - '@angular/common': SystemJS.newModule(AngularCommon), - '@angular/common/http': SystemJS.newModule(HttpClientModule), - '@angular/forms': SystemJS.newModule(AngularForms), - '@angular/flex-layout': SystemJS.newModule(AngularFlexLayout), - '@angular/platform-browser': SystemJS.newModule(AngularPlatformBrowser), - '@angular/router': SystemJS.newModule(AngularRouter), - '@angular/cdk/coercion': SystemJS.newModule(AngularCdkCoercion), - '@angular/cdk/collections': SystemJS.newModule(AngularCdkCollections), - '@angular/cdk/keycodes': SystemJS.newModule(AngularCdkKeycodes), - '@angular/cdk/layout': SystemJS.newModule(AngularCdkLayout), - '@angular/cdk/overlay': SystemJS.newModule(AngularCdkOverlay), - '@angular/cdk/portal': SystemJS.newModule(AngularCdkPortal), - '@angular/cdk/drag-drop': SystemJS.newModule(DragDropModule), - '@angular/material/autocomplete': SystemJS.newModule(AngularMaterialAutocomplete), - '@angular/material/badge': SystemJS.newModule(AngularMaterialBadge), - '@angular/material/bottom-sheet': SystemJS.newModule(AngularMaterialBottomSheet), - '@angular/material/button': SystemJS.newModule(AngularMaterialButton), - '@angular/material/button-toggle': SystemJS.newModule(AngularMaterialButtonToggle), - '@angular/material/card': SystemJS.newModule(AngularMaterialCard), - '@angular/material/checkbox': SystemJS.newModule(AngularMaterialCheckbox), - '@angular/material/chips': SystemJS.newModule(AngularMaterialChips), - '@angular/material/core': SystemJS.newModule(AngularMaterialCore), - '@angular/material/datepicker': SystemJS.newModule(AngularMaterialDatepicker), - '@angular/material/dialog': SystemJS.newModule(AngularMaterialDialog), - '@angular/material/divider': SystemJS.newModule(AngularMaterialDivider), - '@angular/material/expansion': SystemJS.newModule(AngularMaterialExpansion), - '@angular/material/form-field': SystemJS.newModule(AngularMaterialFormField), - '@angular/material/grid-list': SystemJS.newModule(AngularMaterialGridList), - '@angular/material/icon': SystemJS.newModule(AngularMaterialIcon), - '@angular/material/input': SystemJS.newModule(AngularMaterialInput), - '@angular/material/list': SystemJS.newModule(AngularMaterialList), - '@angular/material/menu': SystemJS.newModule(AngularMaterialMenu), - '@angular/material/paginator': SystemJS.newModule(AngularMaterialPaginator), - '@angular/material/progress-bar': SystemJS.newModule(AngularMaterialProgressBar), - '@angular/material/progress-spinner': SystemJS.newModule(AngularMaterialProgressSpinner), - '@angular/material/radio': SystemJS.newModule(AngularMaterialRadio), - '@angular/material/select': SystemJS.newModule(AngularMaterialSelect), - '@angular/material/sidenav': SystemJS.newModule(AngularMaterialSidenav), - '@angular/material/slide-toggle': SystemJS.newModule(AngularMaterialSlideToggle), - '@angular/material/slider': SystemJS.newModule(AngularMaterialSlider), - '@angular/material/snack-bar': SystemJS.newModule(AngularMaterialSnackBar), - '@angular/material/sort': SystemJS.newModule(AngularMaterialSort), - '@angular/material/stepper': SystemJS.newModule(AngularMaterialStepper), - '@angular/material/table': SystemJS.newModule(AngularMaterialTable), - '@angular/material/tabs': SystemJS.newModule(AngularMaterialTabs), - '@angular/material/toolbar': SystemJS.newModule(AngularMaterialToolbar), - '@angular/material/tooltip': SystemJS.newModule(AngularMaterialTooltip), - '@angular/material/tree': SystemJS.newModule(AngularMaterialTree), - '@ngrx/store': SystemJS.newModule(NgrxStore), - rxjs: SystemJS.newModule(RxJs), - 'rxjs/operators': SystemJS.newModule(RxJsOperators), - '@ngx-translate/core': SystemJS.newModule(TranslateCore), - '@core/public-api': SystemJS.newModule(TbCore), - '@shared/public-api': SystemJS.newModule(TbShared), - '@home/components/public-api': SystemJS.newModule(TbHomeComponents), - moment: SystemJS.newModule(_moment) -}; + +import * as MillisecondsToTimeStringPipe from '@shared/pipe/milliseconds-to-time-string.pipe'; +import * as EnumToArrayPipe from '@shared/pipe/enum-to-array.pipe'; +import * as HighlightPipe from '@shared/pipe/highlight.pipe'; +import * as TruncatePipe from '@shared/pipe/truncate.pipe'; +import * as TbJsonPipe from '@shared/pipe/tbJson.pipe'; +import * as FileSizePipe from '@shared/pipe/file-size.pipe'; +import * as NospacePipe from '@shared/pipe/nospace.pipe'; +import * as SelectableColumnsPipe from '@shared/pipe/selectable-columns.pipe'; +import * as KeyboardShortcutPipe from '@shared/pipe/keyboard-shortcut.pipe'; + +import * as FooterComponent from '@shared/components/footer.component'; +import * as LogoComponent from '@shared/components/logo.component'; +import * as FooterFabButtonsComponent from '@shared/components/footer-fab-buttons.component'; +import * as FullscreenDirective from '@shared/components/fullscreen.directive'; +import * as CircularProgressDirective from '@shared/components/circular-progress.directive'; +import * as MatChipDraggableDirective from '@shared/components/mat-chip-draggable.directive'; +import * as TbHotkeysDirective from '@shared/components/hotkeys.directive'; +import * as TbAnchorComponent from '@shared/components/tb-anchor.component'; +import * as TbPopoverComponent from '@shared/components/popover.component'; +import * as TbStringTemplateOutletDirective from '@shared/components/directives/sring-template-outlet.directive'; +import * as TbComponentOutletDirective from '@shared/components/directives/component-outlet.directive'; +import * as TbMarkdownComponent from '@shared/components/markdown.component'; +import * as HelpComponent from '@shared/components/help.component'; +import * as HelpMarkdownComponent from '@shared/components/help-markdown.component'; +import * as HelpPopupComponent from '@shared/components/help-popup.component'; +import * as TbCheckboxComponent from '@shared/components/tb-checkbox.component'; +import * as TbToast from '@shared/components/toast.directive'; +import * as TbErrorComponent from '@shared/components/tb-error.component'; +import * as TbCheatSheetComponent from '@shared/components/cheatsheet.component'; +import * as BreadcrumbComponent from '@shared/components/breadcrumb.component'; +import * as UserMenuComponent from '@shared/components/user-menu.component'; +import * as TimewindowComponent from '@shared/components/time/timewindow.component'; +import * as TimewindowPanelComponent from '@shared/components/time/timewindow-panel.component'; +import * as TimeintervalComponent from '@shared/components/time/timeinterval.component'; +import * as QuickTimeIntervalComponent from '@shared/components/time/quick-time-interval.component'; +import * as DashboardSelectComponent from '@shared/components/dashboard-select.component'; +import * as DashboardSelectPanelComponent from '@shared/components/dashboard-select-panel.component'; +import * as DatetimePeriodComponent from '@shared/components/time/datetime-period.component'; +import * as DatetimeComponent from '@shared/components/time/datetime.component'; +import * as TimezoneSelectComponent from '@shared/components/time/timezone-select.component'; +import * as ValueInputComponent from '@shared/components/value-input.component'; +import * as DashboardAutocompleteComponent from '@shared/components/dashboard-autocomplete.component'; +import * as EntitySubTypeAutocompleteComponent from '@shared/components/entity/entity-subtype-autocomplete.component'; +import * as EntitySubTypeSelectComponent from '@shared/components/entity/entity-subtype-select.component'; +import * as EntitySubTypeListComponent from '@shared/components/entity/entity-subtype-list.component'; +import * as EntityAutocompleteComponent from '@shared/components/entity/entity-autocomplete.component'; +import * as EntityListComponent from '@shared/components/entity/entity-list.component'; +import * as EntityTypeSelectComponent from '@shared/components/entity/entity-type-select.component'; +import * as EntitySelectComponent from '@shared/components/entity/entity-select.component'; +import * as EntityKeysListComponent from '@shared/components/entity/entity-keys-list.component'; +import * as EntityListSelectComponent from '@shared/components/entity/entity-list-select.component'; +import * as EntityTypeListComponent from '@shared/components/entity/entity-type-list.component'; +import * as QueueTypeListComponent from '@shared/components/queue/queue-type-list.component'; +import * as RelationTypeAutocompleteComponent from '@shared/components/relation/relation-type-autocomplete.component'; +import * as SocialSharePanelComponent from '@shared/components/socialshare-panel.component'; +import * as JsonObjectEditComponent from '@shared/components/json-object-edit.component'; +import * as JsonContentComponent from '@shared/components/json-content.component'; +import * as JsFuncComponent from '@shared/components/js-func.component'; +import * as FabToolbarComponent from '@shared/components/fab-toolbar.component'; +import * as WidgetsBundleSelectComponent from '@shared/components/widgets-bundle-select.component'; +import * as ConfirmDialogComponent from '@shared/components/dialog/confirm-dialog.component'; +import * as AlertDialogComponent from '@shared/components/dialog/alert-dialog.component'; +import * as TodoDialogComponent from '@shared/components/dialog/todo-dialog.component'; +import * as ColorPickerDialogComponent from '@shared/components/dialog/color-picker-dialog.component'; +import * as MaterialIconsDialogComponent from '@shared/components/dialog/material-icons-dialog.component'; +import * as ColorInputComponent from '@shared/components/color-input.component'; +import * as MaterialIconSelectComponent from '@shared/components/material-icon-select.component'; +import * as NodeScriptTestDialogComponent from '@shared/components/dialog/node-script-test-dialog.component'; +import * as JsonFormComponent from '@shared/components/json-form/json-form.component'; +import * as ImageInputComponent from '@shared/components/image-input.component'; +import * as FileInputComponent from '@shared/components/file-input.component'; +import * as MessageTypeAutocompleteComponent from '@shared/components/message-type-autocomplete.component'; +import * as KeyValMapComponent from '@shared/components/kv-map.component'; +import * as NavTreeComponent from '@shared/components/nav-tree.component'; +import * as LedLightComponent from '@shared/components/led-light.component'; +import * as TbJsonToStringDirective from '@shared/components/directives/tb-json-to-string.directive'; +import * as JsonObjectEditDialogComponent from '@shared/components/dialog/json-object-edit-dialog.component'; +import * as HistorySelectorComponent from '@shared/components/time/history-selector/history-selector.component'; +import * as EntityGatewaySelectComponent from '@shared/components/entity/entity-gateway-select.component'; +import * as ContactComponent from '@shared/components/contact.component'; +import * as OtaPackageAutocompleteComponent from '@shared/components/ota-package/ota-package-autocomplete.component'; +import * as WidgetsBundleSearchComponent from '@shared/components/widgets-bundle-search.component'; +import * as CopyButtonComponent from '@shared/components/button/copy-button.component'; +import * as TogglePasswordComponent from '@shared/components/button/toggle-password.component'; +import * as ProtobufContentComponent from '@shared/components/protobuf-content.component'; + +import * as AddEntityDialogComponent from '@home/components/entity/add-entity-dialog.component'; +import * as EntitiesTableComponent from '@home/components/entity/entities-table.component'; +import * as DetailsPanelComponent from '@home/components/details-panel.component'; +import * as EntityDetailsPanelComponent from '@home/components/entity/entity-details-panel.component'; +import * as AuditLogDetailsDialogComponent from '@home/components/audit-log/audit-log-details-dialog.component'; +import * as AuditLogTableComponent from '@home/components/audit-log/audit-log-table.component'; +import * as EventTableHeaderComponent from '@home/components/event/event-table-header.component'; +import * as EventTableComponent from '@home/components/event/event-table.component'; +import * as EventFilterPanelComponent from '@home/components/event/event-filter-panel.component'; +import * as RelationTableComponent from '@home/components/relation/relation-table.component'; +import * as RelationDialogComponent from '@home/components/relation/relation-dialog.component'; +import * as AlarmTableHeaderComponent from '@home/components/alarm/alarm-table-header.component'; +import * as AlarmTableComponent from '@home/components/alarm/alarm-table.component'; +import * as AttributeTableComponent from '@home/components/attribute/attribute-table.component'; +import * as AddAttributeDialogComponent from '@home/components/attribute/add-attribute-dialog.component'; +import * as EditAttributeValuePanelComponent from '@home/components/attribute/edit-attribute-value-panel.component'; +import * as DashboardComponent from '@home/components/dashboard/dashboard.component'; +import * as WidgetComponent from '@home/components/widget/widget.component'; +import * as LegendComponent from '@home/components/widget/legend.component'; +import * as AliasesEntitySelectPanelComponent from '@home/components/alias/aliases-entity-select-panel.component'; +import * as AliasesEntitySelectComponent from '@home/components/alias/aliases-entity-select.component'; +import * as WidgetConfigComponent from '@home/components/widget/widget-config.component'; +import * as EntityAliasesDialogComponent from '@home/components/alias/entity-aliases-dialog.component'; +import * as EntityFilterViewComponent from '@home/components/entity/entity-filter-view.component'; +import * as EntityAliasDialogComponent from '@home/components/alias/entity-alias-dialog.component'; +import * as EntityFilterComponent from '@home/components/entity/entity-filter.component'; +import * as RelationFiltersComponent from '@home/components/relation/relation-filters.component'; +import * as EntityAliasSelectComponent from '@home/components/alias/entity-alias-select.component'; +import * as DataKeysComponent from '@home/components/widget/data-keys.component'; +import * as DataKeyConfigDialogComponent from '@home/components/widget/data-key-config-dialog.component'; +import * as DataKeyConfigComponent from '@home/components/widget/data-key-config.component'; +import * as LegendConfigComponent from '@home/components/widget/legend-config.component'; +import * as ManageWidgetActionsComponent from '@home/components/widget/action/manage-widget-actions.component'; +import * as WidgetActionDialogComponent from '@home/components/widget/action/widget-action-dialog.component'; +import * as CustomActionPrettyResourcesTabsComponent from '@home/components/widget/action/custom-action-pretty-resources-tabs.component'; +import * as CustomActionPrettyEditorComponent from '@home/components/widget/action/custom-action-pretty-editor.component'; +import * as MobileActionEditorComponent from '@home/components/widget/action/mobile-action-editor.component'; +import * as CustomDialogService from '@home/components/widget/dialog/custom-dialog.service'; +import * as CustomDialogContainerComponent from '@home/components/widget/dialog/custom-dialog-container.component'; +import * as ImportDialogComponent from '@home/components/import-export/import-dialog.component'; +import * as AddWidgetToDashboardDialogComponent from '@home/components/attribute/add-widget-to-dashboard-dialog.component'; +import * as ImportDialogCsvComponent from '@home/components/import-export/import-dialog-csv.component'; +import * as TableColumnsAssignmentComponent from '@home/components/import-export/table-columns-assignment.component'; +import * as EventContentDialogComponent from '@home/components/event/event-content-dialog.component'; +import * as SharedHomeComponentsModule from '@home/components/shared-home-components.module'; +import * as SelectTargetLayoutDialogComponent from '@home/components/dashboard/select-target-layout-dialog.component'; +import * as SelectTargetStateDialogComponent from '@home/components/dashboard/select-target-state-dialog.component'; +import * as AliasesEntityAutocompleteComponent from '@home/components/alias/aliases-entity-autocomplete.component'; +import * as BooleanFilterPredicateComponent from '@home/components/filter/boolean-filter-predicate.component'; +import * as StringFilterPredicateComponent from '@home/components/filter/string-filter-predicate.component'; +import * as NumericFilterPredicateComponent from '@home/components/filter/numeric-filter-predicate.component'; +import * as ComplexFilterPredicateComponent from '@home/components/filter/complex-filter-predicate.component'; +import * as FilterPredicateComponent from '@home/components/filter/filter-predicate.component'; +import * as FilterPredicateListComponent from '@home/components/filter/filter-predicate-list.component'; +import * as KeyFilterListComponent from '@home/components/filter/key-filter-list.component'; +import * as ComplexFilterPredicateDialogComponent from '@home/components/filter/complex-filter-predicate-dialog.component'; +import * as KeyFilterDialogComponent from '@home/components/filter/key-filter-dialog.component'; +import * as FiltersDialogComponent from '@home/components/filter/filters-dialog.component'; +import * as FilterDialogComponent from '@home/components/filter/filter-dialog.component'; +import * as FilterSelectComponent from '@home/components/filter/filter-select.component'; +import * as FiltersEditComponent from '@home/components/filter/filters-edit.component'; +import * as FiltersEditPanelComponent from '@home/components/filter/filters-edit-panel.component'; +import * as UserFilterDialogComponent from '@home/components/filter/user-filter-dialog.component'; +import * as FilterUserInfoComponent from '@home/components/filter/filter-user-info.component'; +import * as FilterUserInfoDialogComponent from '@home/components/filter/filter-user-info-dialog.component'; +import * as FilterPredicateValueComponent from '@home/components/filter/filter-predicate-value.component'; +import * as TenantProfileComponent from '@home/components/profile/tenant-profile.component'; +import * as TenantProfileDialogComponent from '@home/components/profile/tenant-profile-dialog.component'; +import * as TenantProfileDataComponent from '@home/components/profile/tenant-profile-data.component'; +// tslint:disable-next-line:max-line-length +import * as DefaultDeviceProfileConfigurationComponent from '@home/components/profile/device/default-device-profile-configuration.component'; +import * as DeviceProfileConfigurationComponent from '@home/components/profile/device/device-profile-configuration.component'; +import * as DeviceProfileComponent from '@home/components/profile/device-profile.component'; +import * as DefaultDeviceProfileTransportConfigurationComponent from '@home/components/profile/device/default-device-profile-transport-configuration.component'; +import * as DeviceProfileTransportConfigurationComponent from '@home/components/profile/device/device-profile-transport-configuration.component'; +import * as DeviceProfileDialogComponent from '@home/components/profile/device-profile-dialog.component'; +import * as DeviceProfileAutocompleteComponent from '@home/components/profile/device-profile-autocomplete.component'; +import * as MqttDeviceProfileTransportConfigurationComponent from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component'; +import * as CoapDeviceProfileTransportConfigurationComponent from '@home/components/profile/device/coap-device-profile-transport-configuration.component'; +import * as DeviceProfileAlarmsComponent from '@home/components/profile/alarm/device-profile-alarms.component'; +import * as DeviceProfileAlarmComponent from '@home/components/profile/alarm/device-profile-alarm.component'; +import * as CreateAlarmRulesComponent from '@home/components/profile/alarm/create-alarm-rules.component'; +import * as AlarmRuleComponent from '@home/components/profile/alarm/alarm-rule.component'; +import * as AlarmRuleConditionComponent from '@home/components/profile/alarm/alarm-rule-condition.component'; +import * as FilterTextComponent from '@home/components/filter/filter-text.component'; +import * as AddDeviceProfileDialogComponent from '@home/components/profile/add-device-profile-dialog.component'; +import * as RuleChainAutocompleteComponent from '@home/components/rule-chain/rule-chain-autocomplete.component'; +import * as DeviceProfileProvisionConfigurationComponent from '@home/components/profile/device-profile-provision-configuration.component'; +import * as AlarmScheduleComponent from '@home/components/profile/alarm/alarm-schedule.component'; +import * as DeviceWizardDialogComponent from '@home/components/wizard/device-wizard-dialog.component'; +import * as AlarmScheduleInfoComponent from '@home/components/profile/alarm/alarm-schedule-info.component'; +import * as AlarmScheduleDialogComponent from '@home/components/profile/alarm/alarm-schedule-dialog.component'; +import * as EditAlarmDetailsDialogComponent from '@home/components/profile/alarm/edit-alarm-details-dialog.component'; +import * as AlarmRuleConditionDialogComponent from '@home/components/profile/alarm/alarm-rule-condition-dialog.component'; +// tslint:disable-next-line:max-line-length +import * as DefaultTenantProfileConfigurationComponent from '@home/components/profile/tenant/default-tenant-profile-configuration.component'; +import * as TenantProfileConfigurationComponent from '@home/components/profile/tenant/tenant-profile-configuration.component'; +import * as SmsProviderConfigurationComponent from '@home/components/sms/sms-provider-configuration.component'; +import * as AwsSnsProviderConfigurationComponent from '@home/components/sms/aws-sns-provider-configuration.component'; +import * as TwilioSmsProviderConfigurationComponent from '@home/components/sms/twilio-sms-provider-configuration.component'; +import * as DashboardPageComponent from '@home/components/dashboard-page/dashboard-page.component'; +import * as DashboardToolbarComponent from '@home/components/dashboard-page/dashboard-toolbar.component'; +import * as DashboardLayoutComponent from '@home/components/dashboard-page/layout/dashboard-layout.component'; +import * as EditWidgetComponent from '@home/components/dashboard-page/edit-widget.component'; +import * as DashboardWidgetSelectComponent from '@home/components/dashboard-page/dashboard-widget-select.component'; +import * as AddWidgetDialogComponent from '@home/components/dashboard-page/add-widget-dialog.component'; +import * as ManageDashboardLayoutsDialogComponent from '@home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component'; +import * as DashboardSettingsDialogComponent from '@home/components/dashboard-page/dashboard-settings-dialog.component'; +import * as ManageDashboardStatesDialogComponent from '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component'; +import * as DashboardStateDialogComponent from '@home/components/dashboard-page/states/dashboard-state-dialog.component'; +import * as EmbedDashboardDialogComponent from '@home/components/widget/dialog/embed-dashboard-dialog.component'; +import * as EdgeDownlinkTableComponent from '@home/components/edge/edge-downlink-table.component'; +import * as EdgeDownlinkTableHeaderComponent from '@home/components/edge/edge-downlink-table-header.component'; +import * as DisplayWidgetTypesPanelComponent from '@home/components/dashboard-page/widget-types-panel.component'; +import * as AlarmDurationPredicateValueComponent from '@home/components/profile/alarm/alarm-duration-predicate-value.component'; +import * as DashboardImageDialogComponent from '@home/components/dashboard-page/dashboard-image-dialog.component'; +import * as WidgetContainerComponent from '@home/components/widget/widget-container.component'; + +import { IModulesMap } from '@modules/common/modules-map.models'; + +declare const System; + +class ModulesMap implements IModulesMap { + + private initialized = false; + + private modulesMap: {[key: string]: any} = { + '@angular/animations': AngularAnimations, + '@angular/core': AngularCore, + '@angular/common': AngularCommon, + '@angular/common/http': HttpClientModule, + '@angular/forms': AngularForms, + '@angular/flex-layout': AngularFlexLayout, + '@angular/flex-layout/flex': AngularFlexLayoutFlex, + '@angular/flex-layout/grid': AngularFlexLayoutGrid, + '@angular/flex-layout/extended': AngularFlexLayoutExtended, + '@angular/platform-browser': AngularPlatformBrowser, + '@angular/router': AngularRouter, + '@angular/cdk/coercion': AngularCdkCoercion, + '@angular/cdk/collections': AngularCdkCollections, + '@angular/cdk/keycodes': AngularCdkKeycodes, + '@angular/cdk/layout': AngularCdkLayout, + '@angular/cdk/overlay': AngularCdkOverlay, + '@angular/cdk/portal': AngularCdkPortal, + '@angular/cdk/drag-drop': DragDropModule, + '@angular/material/autocomplete': AngularMaterialAutocomplete, + '@angular/material/badge': AngularMaterialBadge, + '@angular/material/bottom-sheet': AngularMaterialBottomSheet, + '@angular/material/button': AngularMaterialButton, + '@angular/material/button-toggle': AngularMaterialButtonToggle, + '@angular/material/card': AngularMaterialCard, + '@angular/material/checkbox': AngularMaterialCheckbox, + '@angular/material/chips': AngularMaterialChips, + '@angular/material/core': AngularMaterialCore, + '@angular/material/datepicker': AngularMaterialDatepicker, + '@angular/material/dialog': AngularMaterialDialog, + '@angular/material/divider': AngularMaterialDivider, + '@angular/material/expansion': AngularMaterialExpansion, + '@angular/material/form-field': AngularMaterialFormField, + '@angular/material/grid-list': AngularMaterialGridList, + '@angular/material/icon': AngularMaterialIcon, + '@angular/material/input': AngularMaterialInput, + '@angular/material/list': AngularMaterialList, + '@angular/material/menu': AngularMaterialMenu, + '@angular/material/paginator': AngularMaterialPaginator, + '@angular/material/progress-bar': AngularMaterialProgressBar, + '@angular/material/progress-spinner': AngularMaterialProgressSpinner, + '@angular/material/radio': AngularMaterialRadio, + '@angular/material/select': AngularMaterialSelect, + '@angular/material/sidenav': AngularMaterialSidenav, + '@angular/material/slide-toggle': AngularMaterialSlideToggle, + '@angular/material/slider': AngularMaterialSlider, + '@angular/material/snack-bar': AngularMaterialSnackBar, + '@angular/material/sort': AngularMaterialSort, + '@angular/material/stepper': AngularMaterialStepper, + '@angular/material/table': AngularMaterialTable, + '@angular/material/tabs': AngularMaterialTabs, + '@angular/material/toolbar': AngularMaterialToolbar, + '@angular/material/tooltip': AngularMaterialTooltip, + '@angular/material/tree': AngularMaterialTree, + '@ngrx/store': NgrxStore, + rxjs: RxJs, + 'rxjs/operators': RxJsOperators, + '@ngx-translate/core': TranslateCore, + moment: _moment, + + '@core/public-api': TbCore, + '@shared/public-api': TbShared, + '@home/components/public-api': TbHomeComponents, + + '@shared/pipe/milliseconds-to-time-string.pipe': MillisecondsToTimeStringPipe, + '@shared/pipe/enum-to-array.pipe': EnumToArrayPipe, + '@shared/pipe/highlight.pipe': HighlightPipe, + '@shared/pipe/truncate.pipe': TruncatePipe, + '@shared/pipe/tbJson.pipe': TbJsonPipe, + '@shared/pipe/file-size.pipe': FileSizePipe, + '@shared/pipe/nospace.pipe': NospacePipe, + '@shared/pipe/selectable-columns.pipe': SelectableColumnsPipe, + '@shared/pipe/keyboard-shortcut.pipe': KeyboardShortcutPipe, + + '@shared/components/footer.component': FooterComponent, + '@shared/components/logo.component': LogoComponent, + '@shared/components/footer-fab-buttons.component': FooterFabButtonsComponent, + '@shared/components/fullscreen.directive': FullscreenDirective, + '@shared/components/circular-progress.directive': CircularProgressDirective, + '@shared/components/mat-chip-draggable.directive': MatChipDraggableDirective, + '@shared/components/hotkeys.directive': TbHotkeysDirective, + '@shared/components/tb-anchor.component': TbAnchorComponent, + '@shared/components/popover.component': TbPopoverComponent, + '@shared/components/directives/sring-template-outlet.directive': TbStringTemplateOutletDirective, + '@shared/components/directives/component-outlet.directive': TbComponentOutletDirective, + '@shared/components/markdown.component': TbMarkdownComponent, + '@shared/components/help.component': HelpComponent, + '@shared/components/help-markdown.component': HelpMarkdownComponent, + '@shared/components/help-popup.component': HelpPopupComponent, + '@shared/components/tb-checkbox.component': TbCheckboxComponent, + '@shared/components/toast.directive': TbToast, + '@shared/components/tb-error.component': TbErrorComponent, + '@shared/components/cheatsheet.component': TbCheatSheetComponent, + '@shared/components/breadcrumb.component': BreadcrumbComponent, + '@shared/components/user-menu.component': UserMenuComponent, + '@shared/components/time/timewindow.component': TimewindowComponent, + '@shared/components/time/timewindow-panel.component': TimewindowPanelComponent, + '@shared/components/time/timeinterval.component': TimeintervalComponent, + '@shared/components/time/quick-time-interval.component': QuickTimeIntervalComponent, + '@shared/components/dashboard-select.component': DashboardSelectComponent, + '@shared/components/dashboard-select-panel.component': DashboardSelectPanelComponent, + '@shared/components/time/datetime-period.component': DatetimePeriodComponent, + '@shared/components/time/datetime.component': DatetimeComponent, + '@shared/components/time/timezone-select.component': TimezoneSelectComponent, + '@shared/components/value-input.component': ValueInputComponent, + '@shared/components/dashboard-autocomplete.component': DashboardAutocompleteComponent, + '@shared/components/entity/entity-subtype-autocomplete.component': EntitySubTypeAutocompleteComponent, + '@shared/components/entity/entity-subtype-select.component': EntitySubTypeSelectComponent, + '@shared/components/entity/entity-subtype-list.component': EntitySubTypeListComponent, + '@shared/components/entity/entity-autocomplete.component': EntityAutocompleteComponent, + '@shared/components/entity/entity-list.component': EntityListComponent, + '@shared/components/entity/entity-type-select.component': EntityTypeSelectComponent, + '@shared/components/entity/entity-select.component': EntitySelectComponent, + '@shared/components/entity/entity-keys-list.component': EntityKeysListComponent, + '@shared/components/entity/entity-list-select.component': EntityListSelectComponent, + '@shared/components/entity/entity-type-list.component': EntityTypeListComponent, + '@shared/components/queue/queue-type-list.component': QueueTypeListComponent, + '@shared/components/relation/relation-type-autocomplete.component': RelationTypeAutocompleteComponent, + '@shared/components/socialshare-panel.component': SocialSharePanelComponent, + '@shared/components/json-object-edit.component': JsonObjectEditComponent, + '@shared/components/json-content.component': JsonContentComponent, + '@shared/components/js-func.component': JsFuncComponent, + '@shared/components/fab-toolbar.component': FabToolbarComponent, + '@shared/components/widgets-bundle-select.component': WidgetsBundleSelectComponent, + '@shared/components/dialog/confirm-dialog.component': ConfirmDialogComponent, + '@shared/components/dialog/alert-dialog.component': AlertDialogComponent, + '@shared/components/dialog/todo-dialog.component': TodoDialogComponent, + '@shared/components/dialog/color-picker-dialog.component': ColorPickerDialogComponent, + '@shared/components/dialog/material-icons-dialog.component': MaterialIconsDialogComponent, + '@shared/components/color-input.component': ColorInputComponent, + '@shared/components/material-icon-select.component': MaterialIconSelectComponent, + '@shared/components/dialog/node-script-test-dialog.component': NodeScriptTestDialogComponent, + '@shared/components/json-form/json-form.component': JsonFormComponent, + '@shared/components/image-input.component': ImageInputComponent, + '@shared/components/file-input.component': FileInputComponent, + '@shared/components/message-type-autocomplete.component': MessageTypeAutocompleteComponent, + '@shared/components/kv-map.component': KeyValMapComponent, + '@shared/components/nav-tree.component': NavTreeComponent, + '@shared/components/led-light.component': LedLightComponent, + '@shared/components/directives/tb-json-to-string.directive': TbJsonToStringDirective, + '@shared/components/dialog/json-object-edit-dialog.component': JsonObjectEditDialogComponent, + '@shared/components/time/history-selector/history-selector.component': HistorySelectorComponent, + '@shared/components/entity/entity-gateway-select.component': EntityGatewaySelectComponent, + '@shared/components/contact.component': ContactComponent, + '@shared/components/ota-package/ota-package-autocomplete.component': OtaPackageAutocompleteComponent, + '@shared/components/widgets-bundle-search.component': WidgetsBundleSearchComponent, + '@shared/components/button/copy-button.component': CopyButtonComponent, + '@shared/components/button/toggle-password.component': TogglePasswordComponent, + '@shared/components/protobuf-content.component': ProtobufContentComponent, + + '@home/components/entity/add-entity-dialog.component': AddEntityDialogComponent, + '@home/components/entity/entities-table.component': EntitiesTableComponent, + '@home/components/details-panel.component': DetailsPanelComponent, + '@home/components/entity/entity-details-panel.component': EntityDetailsPanelComponent, + '@home/components/audit-log/audit-log-details-dialog.component': AuditLogDetailsDialogComponent, + '@home/components/audit-log/audit-log-table.component': AuditLogTableComponent, + '@home/components/event/event-table-header.component': EventTableHeaderComponent, + '@home/components/event/event-table.component': EventTableComponent, + '@home/components/event/event-filter-panel.component': EventFilterPanelComponent, + '@home/components/relation/relation-table.component': RelationTableComponent, + '@home/components/relation/relation-dialog.component': RelationDialogComponent, + '@home/components/alarm/alarm-table-header.component': AlarmTableHeaderComponent, + '@home/components/alarm/alarm-table.component': AlarmTableComponent, + '@home/components/attribute/attribute-table.component': AttributeTableComponent, + '@home/components/attribute/add-attribute-dialog.component': AddAttributeDialogComponent, + '@home/components/attribute/edit-attribute-value-panel.component': EditAttributeValuePanelComponent, + '@home/components/dashboard/dashboard.component': DashboardComponent, + '@home/components/widget/widget.component': WidgetComponent, + '@home/components/widget/legend.component': LegendComponent, + '@home/components/alias/aliases-entity-select-panel.component': AliasesEntitySelectPanelComponent, + '@home/components/alias/aliases-entity-select.component': AliasesEntitySelectComponent, + '@home/components/widget/widget-config.component': WidgetConfigComponent, + '@home/components/alias/entity-aliases-dialog.component': EntityAliasesDialogComponent, + '@home/components/entity/entity-filter-view.component': EntityFilterViewComponent, + '@home/components/alias/entity-alias-dialog.component': EntityAliasDialogComponent, + '@home/components/entity/entity-filter.component': EntityFilterComponent, + '@home/components/relation/relation-filters.component': RelationFiltersComponent, + '@home/components/alias/entity-alias-select.component': EntityAliasSelectComponent, + '@home/components/widget/data-keys.component': DataKeysComponent, + '@home/components/widget/data-key-config-dialog.component': DataKeyConfigDialogComponent, + '@home/components/widget/data-key-config.component': DataKeyConfigComponent, + '@home/components/widget/legend-config.component': LegendConfigComponent, + '@home/components/widget/action/manage-widget-actions.component': ManageWidgetActionsComponent, + '@home/components/widget/action/widget-action-dialog.component': WidgetActionDialogComponent, + '@home/components/widget/action/custom-action-pretty-resources-tabs.component': CustomActionPrettyResourcesTabsComponent, + '@home/components/widget/action/custom-action-pretty-editor.component': CustomActionPrettyEditorComponent, + '@home/components/widget/action/mobile-action-editor.component': MobileActionEditorComponent, + '@home/components/widget/dialog/custom-dialog.service': CustomDialogService, + '@home/components/widget/dialog/custom-dialog-container.component': CustomDialogContainerComponent, + '@home/components/import-export/import-dialog.component': ImportDialogComponent, + '@home/components/attribute/add-widget-to-dashboard-dialog.component': AddWidgetToDashboardDialogComponent, + '@home/components/import-export/import-dialog-csv.component': ImportDialogCsvComponent, + '@home/components/import-export/table-columns-assignment.component': TableColumnsAssignmentComponent, + '@home/components/event/event-content-dialog.component': EventContentDialogComponent, + '@home/components/shared-home-components.module': SharedHomeComponentsModule, + '@home/components/dashboard/select-target-layout-dialog.component': SelectTargetLayoutDialogComponent, + '@home/components/dashboard/select-target-state-dialog.component': SelectTargetStateDialogComponent, + '@home/components/alias/aliases-entity-autocomplete.component': AliasesEntityAutocompleteComponent, + '@home/components/filter/boolean-filter-predicate.component': BooleanFilterPredicateComponent, + '@home/components/filter/string-filter-predicate.component': StringFilterPredicateComponent, + '@home/components/filter/numeric-filter-predicate.component': NumericFilterPredicateComponent, + '@home/components/filter/complex-filter-predicate.component': ComplexFilterPredicateComponent, + '@home/components/filter/filter-predicate.component': FilterPredicateComponent, + '@home/components/filter/filter-predicate-list.component': FilterPredicateListComponent, + '@home/components/filter/key-filter-list.component': KeyFilterListComponent, + '@home/components/filter/complex-filter-predicate-dialog.component': ComplexFilterPredicateDialogComponent, + '@home/components/filter/key-filter-dialog.component': KeyFilterDialogComponent, + '@home/components/filter/filters-dialog.component': FiltersDialogComponent, + '@home/components/filter/filter-dialog.component': FilterDialogComponent, + '@home/components/filter/filter-select.component': FilterSelectComponent, + '@home/components/filter/filters-edit.component': FiltersEditComponent, + '@home/components/filter/filters-edit-panel.component': FiltersEditPanelComponent, + '@home/components/filter/user-filter-dialog.component': UserFilterDialogComponent, + '@home/components/filter/filter-user-info.component': FilterUserInfoComponent, + '@home/components/filter/filter-user-info-dialog.component': FilterUserInfoDialogComponent, + '@home/components/filter/filter-predicate-value.component': FilterPredicateValueComponent, + '@home/components/profile/tenant-profile.component': TenantProfileComponent, + '@home/components/profile/tenant-profile-dialog.component': TenantProfileDialogComponent, + '@home/components/profile/tenant-profile-data.component': TenantProfileDataComponent, + '@home/components/profile/device/default-device-profile-configuration.component': DefaultDeviceProfileConfigurationComponent, + '@home/components/profile/device/device-profile-configuration.component': DeviceProfileConfigurationComponent, + '@home/components/profile/device-profile.component': DeviceProfileComponent, + '@home/components/profile/device/default-device-profile-transport-configuration.component': + DefaultDeviceProfileTransportConfigurationComponent, + '@home/components/profile/device/device-profile-transport-configuration.component': DeviceProfileTransportConfigurationComponent, + '@home/components/profile/device-profile-dialog.component': DeviceProfileDialogComponent, + '@home/components/profile/device-profile-autocomplete.component': DeviceProfileAutocompleteComponent, + '@home/components/profile/device/mqtt-device-profile-transport-configuration.component': + MqttDeviceProfileTransportConfigurationComponent, + '@home/components/profile/device/coap-device-profile-transport-configuration.component': + CoapDeviceProfileTransportConfigurationComponent, + '@home/components/profile/alarm/device-profile-alarms.component': DeviceProfileAlarmsComponent, + '@home/components/profile/alarm/device-profile-alarm.component': DeviceProfileAlarmComponent, + '@home/components/profile/alarm/create-alarm-rules.component': CreateAlarmRulesComponent, + '@home/components/profile/alarm/alarm-rule.component': AlarmRuleComponent, + '@home/components/profile/alarm/alarm-rule-condition.component': AlarmRuleConditionComponent, + '@home/components/filter/filter-text.component': FilterTextComponent, + '@home/components/profile/add-device-profile-dialog.component': AddDeviceProfileDialogComponent, + '@home/components/rule-chain/rule-chain-autocomplete.component': RuleChainAutocompleteComponent, + '@home/components/profile/device-profile-provision-configuration.component': DeviceProfileProvisionConfigurationComponent, + '@home/components/profile/alarm/alarm-schedule.component': AlarmScheduleComponent, + '@home/components/wizard/device-wizard-dialog.component': DeviceWizardDialogComponent, + '@home/components/profile/alarm/alarm-schedule-info.component': AlarmScheduleInfoComponent, + '@home/components/profile/alarm/alarm-schedule-dialog.component': AlarmScheduleDialogComponent, + '@home/components/profile/alarm/edit-alarm-details-dialog.component': EditAlarmDetailsDialogComponent, + '@home/components/profile/alarm/alarm-rule-condition-dialog.component': AlarmRuleConditionDialogComponent, + '@home/components/profile/tenant/default-tenant-profile-configuration.component': DefaultTenantProfileConfigurationComponent, + '@home/components/profile/tenant/tenant-profile-configuration.component': TenantProfileConfigurationComponent, + '@home/components/sms/sms-provider-configuration.component': SmsProviderConfigurationComponent, + '@home/components/sms/aws-sns-provider-configuration.component': AwsSnsProviderConfigurationComponent, + '@home/components/sms/twilio-sms-provider-configuration.component': TwilioSmsProviderConfigurationComponent, + '@home/components/dashboard-page/dashboard-page.component': DashboardPageComponent, + '@home/components/dashboard-page/dashboard-toolbar.component': DashboardToolbarComponent, + '@home/components/dashboard-page/layout/dashboard-layout.component': DashboardLayoutComponent, + '@home/components/dashboard-page/edit-widget.component': EditWidgetComponent, + '@home/components/dashboard-page/dashboard-widget-select.component': DashboardWidgetSelectComponent, + '@home/components/dashboard-page/add-widget-dialog.component': AddWidgetDialogComponent, + '@home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component': ManageDashboardLayoutsDialogComponent, + '@home/components/dashboard-page/dashboard-settings-dialog.component': DashboardSettingsDialogComponent, + '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component': ManageDashboardStatesDialogComponent, + '@home/components/dashboard-page/states/dashboard-state-dialog.component': DashboardStateDialogComponent, + '@home/components/widget/dialog/embed-dashboard-dialog.component': EmbedDashboardDialogComponent, + '@home/components/edge/edge-downlink-table.component': EdgeDownlinkTableComponent, + '@home/components/edge/edge-downlink-table-header.component': EdgeDownlinkTableHeaderComponent, + '@home/components/dashboard-page/widget-types-panel.component': DisplayWidgetTypesPanelComponent, + '@home/components/profile/alarm/alarm-duration-predicate-value.component': AlarmDurationPredicateValueComponent, + '@home/components/dashboard-page/dashboard-image-dialog.component': DashboardImageDialogComponent, + '@home/components/widget/widget-container.component': WidgetContainerComponent, + }; + + init() { + if (!this.initialized) { + System.constructor.prototype.resolve = (id) => { + try { + if (this.modulesMap[id]) { + return 'app:' + id; + } else { + return id; + } + } catch (err) { + return id; + } + }; + for (const moduleId of Object.keys(this.modulesMap)) { + System.set('app:' + moduleId, this.modulesMap[moduleId]); + } + this.initialized = true; + } + } +} + +export const modulesMap = new ModulesMap(); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.module.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.module.ts index 0f8c60858a..66b14fee44 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.module.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.module.ts @@ -17,9 +17,9 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; -import { StatesControllerService } from './states-controller.service'; -import { EntityStateControllerComponent } from './entity-state-controller.component'; -import { StatesComponentDirective } from './states-component.directive'; +import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; +import { EntityStateControllerComponent } from '@home/components/dashboard-page/states/entity-state-controller.component'; +import { StatesComponentDirective } from '@home/components/dashboard-page/states/states-component.directive'; import { HomeDialogsModule } from '@app/modules/home/dialogs/home-dialogs.module'; import { DefaultStateControllerComponent } from '@home/components/dashboard-page/states/default-state-controller.component'; diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.module.ts b/ui-ngx/src/app/modules/home/components/device/device-credentials.module.ts index 49f1c2c097..ce3bbbbd97 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.module.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.module.ts @@ -17,11 +17,11 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; -import { CopyDeviceCredentialsComponent } from './copy-device-credentials.component'; -import { DeviceCredentialsComponent } from './device-credentials.component'; -import { DeviceCredentialsLwm2mComponent } from './device-credentials-lwm2m.component'; -import { DeviceCredentialsLwm2mServerComponent } from './device-credentials-lwm2m-server.component'; -import { DeviceCredentialsMqttBasicComponent } from './device-credentials-mqtt-basic.component'; +import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-device-credentials.component'; +import { DeviceCredentialsComponent } from '@home/components/device/device-credentials.component'; +import { DeviceCredentialsLwm2mComponent } from '@home/components/device/device-credentials-lwm2m.component'; +import { DeviceCredentialsLwm2mServerComponent } from '@home/components/device/device-credentials-lwm2m-server.component'; +import { DeviceCredentialsMqttBasicComponent } from '@home/components/device/device-credentials-mqtt-basic.component'; @NgModule({ declarations: [ diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index 49386db131..33f1b2afe4 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -64,6 +64,7 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; import { isDefined, isUndefined } from '@core/utils'; import { HasUUID } from '@shared/models/id/has-uuid'; +import { IEntitiesTableComponent } from '@home/models/entity/entity-table-component.models'; @Component({ selector: 'tb-entities-table', @@ -71,7 +72,7 @@ import { HasUUID } from '@shared/models/id/has-uuid'; styleUrls: ['./entities-table.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class EntitiesTableComponent extends PageComponent implements AfterViewInit, OnInit, OnChanges { +export class EntitiesTableComponent extends PageComponent implements IEntitiesTableComponent, AfterViewInit, OnInit, OnChanges { @Input() entitiesTableConfig: EntityTableConfig>; diff --git a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.ts index 3f1bb3cace..4d61aa2c89 100644 --- a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.ts @@ -23,22 +23,12 @@ import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Valida import { Router } from '@angular/router'; import { DialogComponent } from '@app/shared/components/dialog.component'; import { - BooleanOperation, booleanOperationTranslationMap, - ComplexFilterPredicate, ComplexFilterPredicateInfo, ComplexOperation, complexOperationTranslationMap, - EntityKeyValueType, - FilterPredicateType, KeyFilterPredicateInfo + ComplexFilterPredicateInfo, + ComplexOperation, + complexOperationTranslationMap, + FilterPredicateType } from '@shared/models/query/query.models'; - -export interface ComplexFilterPredicateDialogData { - complexPredicate: ComplexFilterPredicateInfo; - key: string; - readonly: boolean; - isAdd: boolean; - valueType: EntityKeyValueType; - displayUserParameters: boolean; - allowUserDynamicSource: boolean; - onlyUserDynamicSource: boolean; -} +import { ComplexFilterPredicateDialogData } from '@home/components/filter/filter-component.models'; @Component({ selector: 'tb-complex-filter-predicate-dialog', diff --git a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts index b177f118c0..038ff474ae 100644 --- a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts @@ -14,15 +14,14 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ComplexFilterPredicateInfo, EntityKeyValueType } from '@shared/models/query/query.models'; import { MatDialog } from '@angular/material/dialog'; -import { - ComplexFilterPredicateDialogComponent, - ComplexFilterPredicateDialogData -} from '@home/components/filter/complex-filter-predicate-dialog.component'; import { deepClone } from '@core/utils'; +import { ComplexFilterPredicateDialogData } from '@home/components/filter/filter-component.models'; +import { COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN } from '@home/components/tokens'; +import { ComponentType } from '@angular/cdk/portal'; @Component({ selector: 'tb-complex-filter-predicate', @@ -54,7 +53,8 @@ export class ComplexFilterPredicateComponent implements ControlValueAccessor, On private complexFilterPredicate: ComplexFilterPredicateInfo; - constructor(private dialog: MatDialog) { + constructor(@Inject(COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN) private complexFilterPredicateDialogComponent: ComponentType, + private dialog: MatDialog) { } ngOnInit(): void { @@ -76,8 +76,8 @@ export class ComplexFilterPredicateComponent implements ControlValueAccessor, On } public openComplexFilterDialog() { - this.dialog.open(ComplexFilterPredicateDialogComponent, { + this.dialog.open(this.complexFilterPredicateDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-component.models.ts b/ui-ngx/src/app/modules/home/components/filter/filter-component.models.ts new file mode 100644 index 0000000000..325f89a911 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/filter/filter-component.models.ts @@ -0,0 +1,29 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ComplexFilterPredicateInfo, EntityKeyValueType } from '@shared/models/query/query.models'; + +export interface ComplexFilterPredicateDialogData { + complexPredicate: ComplexFilterPredicateInfo; + key: string; + readonly: boolean; + isAdd: boolean; + valueType: EntityKeyValueType; + displayUserParameters: boolean; + allowUserDynamicSource: boolean; + onlyUserDynamicSource: boolean; +} + diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts index 75c9bd3ce8..e23c135d9b 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -36,12 +36,11 @@ import { EntityKeyValueType, KeyFilterPredicateInfo } from '@shared/models/query/query.models'; -import { - ComplexFilterPredicateDialogComponent, - ComplexFilterPredicateDialogData -} from '@home/components/filter/complex-filter-predicate-dialog.component'; import { MatDialog } from '@angular/material/dialog'; import { map } from 'rxjs/operators'; +import { ComponentType } from '@angular/cdk/portal'; +import { COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN } from '@home/components/tokens'; +import { ComplexFilterPredicateDialogData } from '@home/components/filter/filter-component.models'; @Component({ selector: 'tb-filter-predicate-list', @@ -87,6 +86,7 @@ export class FilterPredicateListComponent implements ControlValueAccessor, Valid private valueChangeSubscription: Subscription = null; constructor(private fb: FormBuilder, + @Inject(COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN) private complexFilterPredicateDialogComponent: ComponentType, private dialog: MatDialog) { } @@ -164,8 +164,8 @@ export class FilterPredicateListComponent implements ControlValueAccessor, Valid } private openComplexFilterDialog(predicate: KeyFilterPredicateInfo): Observable { - return this.dialog.open(ComplexFilterPredicateDialogComponent, { + return this.dialog.open(this.complexFilterPredicateDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 5e0752fcbc..265c5eb659 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -141,6 +141,10 @@ import { WidgetContainerComponent } from '@home/components/widget/widget-contain import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snpm/snmp-device-profile-transport.module'; import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module'; import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module'; +import { + COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN, + DASHBOARD_PAGE_COMPONENT_TOKEN +} from '@home/components/tokens'; @NgModule({ declarations: @@ -375,7 +379,9 @@ import { DeviceProfileCommonModule } from '@home/components/profile/device/commo WidgetComponentService, CustomDialogService, ImportExportService, - {provide: EMBED_DASHBOARD_DIALOG_TOKEN, useValue: EmbedDashboardDialogComponent} + {provide: EMBED_DASHBOARD_DIALOG_TOKEN, useValue: EmbedDashboardDialogComponent}, + {provide: COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN, useValue: ComplexFilterPredicateDialogComponent}, + {provide: DASHBOARD_PAGE_COMPONENT_TOKEN, useValue: DashboardPageComponent} ] }) export class HomeComponentsModule { } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/common/device-profile-common.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/common/device-profile-common.module.ts index 0ddcb507bb..e4bbdc919f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/common/device-profile-common.module.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/common/device-profile-common.module.ts @@ -15,10 +15,10 @@ /// import { NgModule } from '@angular/core'; -import { PowerModeSettingComponent } from './power-mode-setting.component'; +import { PowerModeSettingComponent } from '@home/components/profile/device/common/power-mode-setting.component'; import { SharedModule } from '@shared/shared.module'; import { CommonModule } from '@angular/common'; -import { TimeUnitSelectComponent } from './time-unit-select.component'; +import { TimeUnitSelectComponent } from '@home/components/profile/device/common/time-unit-select.component'; @NgModule({ declarations: [ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts index aa801f84dc..e1c8e9a14c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts @@ -15,19 +15,19 @@ /// import { NgModule } from '@angular/core'; -import { Lwm2mDeviceProfileTransportConfigurationComponent } from './lwm2m-device-profile-transport-configuration.component'; -import { Lwm2mObjectListComponent } from './lwm2m-object-list.component'; -import { Lwm2mObserveAttrTelemetryComponent } from './lwm2m-observe-attr-telemetry.component'; -import { Lwm2mObserveAttrTelemetryResourcesComponent } from './lwm2m-observe-attr-telemetry-resources.component'; -import { Lwm2mAttributesDialogComponent } from './lwm2m-attributes-dialog.component'; -import { Lwm2mAttributesComponent } from './lwm2m-attributes.component'; -import { Lwm2mAttributesKeyListComponent } from './lwm2m-attributes-key-list.component'; -import { Lwm2mDeviceConfigServerComponent } from './lwm2m-device-config-server.component'; -import { Lwm2mObjectAddInstancesDialogComponent } from './lwm2m-object-add-instances-dialog.component'; -import { Lwm2mObjectAddInstancesListComponent } from './lwm2m-object-add-instances-list.component'; +import { Lwm2mDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component'; +import { Lwm2mObjectListComponent } from '@home/components/profile/device/lwm2m/lwm2m-object-list.component'; +import { Lwm2mObserveAttrTelemetryComponent } from '@home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component'; +import { Lwm2mObserveAttrTelemetryResourcesComponent } from '@home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resources.component'; +import { Lwm2mAttributesDialogComponent } from '@home/components/profile/device/lwm2m/lwm2m-attributes-dialog.component'; +import { Lwm2mAttributesComponent } from '@home/components/profile/device/lwm2m/lwm2m-attributes.component'; +import { Lwm2mAttributesKeyListComponent } from '@home/components/profile/device/lwm2m/lwm2m-attributes-key-list.component'; +import { Lwm2mDeviceConfigServerComponent } from '@home/components/profile/device/lwm2m/lwm2m-device-config-server.component'; +import { Lwm2mObjectAddInstancesDialogComponent } from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component'; +import { Lwm2mObjectAddInstancesListComponent } from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@app/shared/shared.module'; -import { Lwm2mObserveAttrTelemetryInstancesComponent } from './lwm2m-observe-attr-telemetry-instances.component'; +import { Lwm2mObserveAttrTelemetryInstancesComponent } from '@home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component'; import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module'; @NgModule({ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts index c0797d9b0e..95b7c0180d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts @@ -18,8 +18,8 @@ import { NgModule } from '@angular/core'; import { SharedModule } from '@shared/shared.module'; import { CommonModule } from '@angular/common'; import { SnmpDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component'; -import { SnmpDeviceProfileCommunicationConfigComponent } from './snmp-device-profile-communication-config.component'; -import { SnmpDeviceProfileMappingComponent } from './snmp-device-profile-mapping.component'; +import { SnmpDeviceProfileCommunicationConfigComponent } from '@home/components/profile/device/snpm/snmp-device-profile-communication-config.component'; +import { SnmpDeviceProfileMappingComponent } from '@home/components/profile/device/snpm/snmp-device-profile-mapping.component'; @NgModule({ declarations: [ diff --git a/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts b/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts index df6764c573..f2c14a535a 100644 --- a/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts @@ -18,8 +18,12 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@app/shared/shared.module'; import { AlarmDetailsDialogComponent } from '@home/components/alarm/alarm-details-dialog.component'; +import { SHARED_HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; @NgModule({ + providers: [ + { provide: SHARED_HOME_COMPONENTS_MODULE_TOKEN, useValue: SharedHomeComponentsModule } + ], declarations: [ AlarmDetailsDialogComponent diff --git a/ui-ngx/src/app/modules/home/components/tokens.ts b/ui-ngx/src/app/modules/home/components/tokens.ts new file mode 100644 index 0000000000..b88ea49a03 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/tokens.ts @@ -0,0 +1,27 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { InjectionToken, Type } from '@angular/core'; +import { ComponentType } from '@angular/cdk/portal'; + +export const SHARED_HOME_COMPONENTS_MODULE_TOKEN: InjectionToken> = + new InjectionToken>('SHARED_HOME_COMPONENTS_MODULE_TOKEN'); + +export const COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN: InjectionToken> = + new InjectionToken>('COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN'); + +export const DASHBOARD_PAGE_COMPONENT_TOKEN: InjectionToken> = + new InjectionToken>('DASHBOARD_PAGE_COMPONENT_TOKEN'); diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts index ac41188485..a2d61a9eaa 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts @@ -14,21 +14,21 @@ /// limitations under the License. /// -import { Injectable, NgModule } from '@angular/core'; +import { Inject, Injectable, Type } from '@angular/core'; import { Observable } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; import { AuthService } from '@core/auth/auth.service'; import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service'; import { CommonModule } from '@angular/common'; -import { SharedModule } from '@shared/shared.module'; import { mergeMap, tap } from 'rxjs/operators'; import { CustomDialogComponent } from './custom-dialog.component'; import { CustomDialogContainerComponent, CustomDialogContainerData } from '@home/components/widget/dialog/custom-dialog-container.component'; -import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module'; +import { SHARED_MODULE_TOKEN } from '@shared/components/tokens'; +import { SHARED_HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; @Injectable() export class CustomDialogService { @@ -37,6 +37,8 @@ export class CustomDialogService { private translate: TranslateService, private authService: AuthService, private dynamicComponentFactoryService: DynamicComponentFactoryService, + @Inject(SHARED_MODULE_TOKEN) private sharedModule: Type, + @Inject(SHARED_HOME_COMPONENTS_MODULE_TOKEN) private sharedHomeComponentsModule: Type, public dialog: MatDialog ) { } @@ -45,7 +47,7 @@ export class CustomDialogService { return this.dynamicComponentFactoryService.createDynamicComponentFactory( class CustomDialogComponentInstance extends CustomDialogComponent {}, template, - [SharedModule, CustomDialogModule, SharedHomeComponentsModule]).pipe( + [this.sharedModule, CommonModule, this.sharedHomeComponentsModule]).pipe( mergeMap((factory) => { const dialogData: CustomDialogContainerData = { controller, @@ -69,15 +71,3 @@ export class CustomDialogService { } -@NgModule({ - declarations: - [ - ], - imports: [ - CommonModule, - SharedModule - ], - exports: [ - ] -}) -class CustomDialogModule { } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index db62775c40..27d6fb5edc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -168,6 +168,7 @@ export default abstract class LeafletMap { this.selectedEntity = data; this.toggleDrawMode(type); } else { + // @ts-ignore this.map.pm.Toolbar.toggleButton(type, false); } }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.scss index b6b1c45e27..2c789bebbd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.scss @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "node_modules/compass-sass-mixins/lib/compass"; $error-height: 14px !default; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/round-switch.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/round-switch.component.scss index 96cdcadeff..7931b05131 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/round-switch.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/round-switch.component.scss @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "node_modules/compass-sass-mixins/lib/compass"; $error-height: 14px !default; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts index 9f7da7a747..90b3087ced 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts @@ -44,6 +44,7 @@ import { SharedModule } from '@shared/shared.module'; import { MODULES_MAP } from '@shared/public-api'; import * as tinycolor_ from 'tinycolor2'; import moment from 'moment'; +import { IModulesMap } from '@modules/common/modules-map.models'; const tinycolor = tinycolor_; @@ -64,7 +65,7 @@ export class WidgetComponentService { private editingWidgetType: WidgetType; constructor(@Inject(WINDOW) private window: Window, - @Optional() @Inject(MODULES_MAP) private modulesMap: {[key: string]: any}, + @Optional() @Inject(MODULES_MAP) private modulesMap: IModulesMap, private dynamicComponentFactoryService: DynamicComponentFactoryService, private widgetService: WidgetService, private utils: UtilsService, diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts index ba692ed122..ad7912cdee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts @@ -30,10 +30,10 @@ import { DateRangeNavigatorPanelComponent, DateRangeNavigatorWidgetComponent } from '@home/components/widget/lib/date-range-navigator/date-range-navigator.component'; -import { MultipleInputWidgetComponent } from './lib/multiple-input-widget.component'; -import { TripAnimationComponent } from './trip-animation/trip-animation.component'; -import { PhotoCameraInputWidgetComponent } from './lib/photo-camera-input.component'; -import { GatewayFormComponent } from './lib/gateway/gateway-form.component'; +import { MultipleInputWidgetComponent } from '@home/components/widget/lib/multiple-input-widget.component'; +import { TripAnimationComponent } from '@home/components/widget/trip-animation/trip-animation.component'; +import { PhotoCameraInputWidgetComponent } from '@home/components/widget/lib/photo-camera-input.component'; +import { GatewayFormComponent } from '@home/components/widget/lib/gateway/gateway-form.component'; import { ImportExportService } from '@home/components/import-export/import-export.service'; import { NavigationCardsWidgetComponent } from '@home/components/widget/lib/navigation-cards-widget.component'; import { NavigationCardWidgetComponent } from '@home/components/widget/lib/navigation-card-widget.component'; @@ -41,7 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges- import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component'; import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component'; import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component'; -import { SelectEntityDialogComponent } from './lib/maps/dialogs/select-entity-dialog.component'; +import { SelectEntityDialogComponent } from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component'; @NgModule({ declarations: diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 05d8686d46..c1208d0241 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -107,9 +107,11 @@ import { ComponentType } from '@angular/cdk/portal'; import { EMBED_DASHBOARD_DIALOG_TOKEN } from '@home/components/widget/dialog/embed-dashboard-dialog-token'; import { MobileService } from '@core/services/mobile.service'; import { DialogService } from '@core/services/dialog.service'; -import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component'; import { PopoverPlacement } from '@shared/components/popover.models'; import { TbPopoverService } from '@shared/components/popover.service'; +import { + DASHBOARD_PAGE_COMPONENT_TOKEN +} from '@home/components/tokens'; @Component({ selector: 'tb-widget', @@ -183,6 +185,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI private renderer: Renderer2, private popoverService: TbPopoverService, @Inject(EMBED_DASHBOARD_DIALOG_TOKEN) private embedDashboardDialogComponent: ComponentType, + @Inject(DASHBOARD_PAGE_COMPONENT_TOKEN) private dashboardPageComponent: ComponentType, private widgetService: WidgetService, private resources: ResourcesService, private timeService: TimeService, @@ -1354,7 +1357,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI ] }); const component = this.popoverService.displayPopover(trigger, this.renderer, - this.widgetContentContainer, DashboardPageComponent, preferredPlacement, hideOnClickOutside, + this.widgetContentContainer, this.dashboardPageComponent, preferredPlacement, hideOnClickOutside, injector, { embed: true, diff --git a/ui-ngx/src/app/modules/home/home.component.ts b/ui-ngx/src/app/modules/home/home.component.ts index 34be8cc8b2..e1ecacc2d4 100644 --- a/ui-ngx/src/app/modules/home/home.component.ts +++ b/ui-ngx/src/app/modules/home/home.component.ts @@ -25,14 +25,12 @@ import { PageComponent } from '@shared/components/page.component'; import { AppState } from '@core/core.state'; import { getCurrentAuthState, selectAuthUser, selectUserDetails } from '@core/auth/auth.selectors'; import { MediaBreakpoints } from '@shared/models/constants'; -import * as _screenfull from 'screenfull'; +import screenfull from 'screenfull'; import { MatSidenav } from '@angular/material/sidenav'; import { AuthState } from '@core/auth/auth.models'; import { WINDOW } from '@core/services/window.service'; import { instanceOfSearchableComponent, ISearchableComponent } from '@home/models/searchable-component.models'; -const screenfull = _screenfull as _screenfull.Screenfull; - @Component({ selector: 'tb-home', templateUrl: './home.component.html', diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index f554329cc2..2f3d58e61f 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -26,11 +26,11 @@ import { Type } from '@angular/core'; import { EntityAction } from './entity-component.models'; import { HasUUID } from '@shared/models/id/has-uuid'; import { PageLink } from '@shared/models/page/page-link'; -import { EntitiesTableComponent } from '@home/components/entity/entities-table.component'; import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component'; import { ActivatedRoute } from '@angular/router'; import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; import { DAY, historyInterval } from '@shared/models/time/time.models'; +import { IEntitiesTableComponent } from '@home/models/entity/entity-table-component.models'; export type EntityBooleanFunction> = (entity: T) => boolean; export type EntityStringFunction> = (entity: T) => string; @@ -140,7 +140,7 @@ export class EntityTableConfig, P extends PageLink = P loadDataOnInit = true; onLoadAction: (route: ActivatedRoute) => void = null; - table: EntitiesTableComponent = null; + table: IEntitiesTableComponent = null; useTimePageLink = false; defaultTimewindowInterval = historyInterval(DAY); entityType: EntityType = null; diff --git a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts new file mode 100644 index 0000000000..20b1d15b32 --- /dev/null +++ b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts @@ -0,0 +1,85 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { BaseData, HasId } from '@shared/models/base-data'; +import { EntityTypeTranslation } from '@shared/models/entity-type.models'; +import { SafeHtml } from '@angular/platform-browser'; +import { PageLink } from '@shared/models/page/page-link'; +import { Timewindow } from '@shared/models/time/time.models'; +import { EntitiesDataSource } from '@home/models/datasource/entity-datasource'; +import { ElementRef, EventEmitter } from '@angular/core'; +import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { EntityAction } from '@home/models/entity/entity-component.models'; +import { + CellActionDescriptor, EntityActionTableColumn, EntityColumn, EntityTableColumn, + EntityTableConfig, + GroupActionDescriptor, + HeaderActionDescriptor +} from '@home/models/entity/entities-table-config.models'; + +export interface IEntitiesTableComponent { + entitiesTableConfig: EntityTableConfig>; + translations: EntityTypeTranslation; + headerActionDescriptors: Array; + groupActionDescriptors: Array>>; + cellActionDescriptors: Array>>; + actionColumns: Array>>; + entityColumns: Array>>; + displayedColumns: string[]; + headerCellStyleCache: Array; + cellContentCache: Array; + cellTooltipCache: Array; + cellStyleCache: Array; + selectionEnabled: boolean; + defaultPageSize: number; + displayPagination: boolean; + pageSizeOptions: number[]; + pageLink: PageLink; + textSearchMode: boolean; + timewindow: Timewindow; + dataSource: EntitiesDataSource>; + isDetailsOpen: boolean; + detailsPanelOpened: EventEmitter; + entityTableHeaderAnchor: TbAnchorComponent; + searchInputField: ElementRef; + paginator: MatPaginator; + sort: MatSort; + + addEnabled(): boolean; + clearSelection(): void; + updateData(closeDetails?: boolean): void; + onRowClick($event: Event, entity): void; + toggleEntityDetails($event: Event, entity); + addEntity($event: Event): void; + onEntityUpdated(entity: BaseData): void; + onEntityAction(action: EntityAction>): void; + deleteEntity($event: Event, entity: BaseData): void; + deleteEntities($event: Event, entities: BaseData[]): void; + onTimewindowChange(): void; + enterFilterMode(): void; + exitFilterMode(): void; + resetSortAndFilter(update?: boolean, preserveTimewindow?: boolean): void; + columnsUpdated(resetData?: boolean): void; + headerCellStyle(column: EntityColumn>): any; + clearCellCache(col: number, row: number): void; + cellContent(entity: BaseData, column: EntityColumn>, row: number): any; + cellTooltip(entity: BaseData, column: EntityColumn>, row: number): string; + cellStyle(entity: BaseData, column: EntityColumn>, row: number): any; + trackByColumnKey(index, column: EntityTableColumn>): string; + trackByEntityId(index: number, entity: BaseData): string; +} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts index d84bdfafcb..80b8dd218e 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts @@ -41,6 +41,7 @@ import { RuleNodeComponentDescriptor } from '@shared/models/rule-node.models'; import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { ItemBufferService } from '@core/public-api'; import { MODULES_MAP } from '@shared/public-api'; +import { IModulesMap } from '@modules/common/modules-map.models'; @Injectable() export class RuleChainResolver implements Resolve { @@ -70,7 +71,7 @@ export class ResolvedRuleChainMetaDataResolver implements Resolve> { constructor(private ruleChainService: RuleChainService, - @Optional() @Inject(MODULES_MAP) private modulesMap: {[key: string]: any}) { + @Optional() @Inject(MODULES_MAP) private modulesMap: IModulesMap) { } resolve(route: ActivatedRouteSnapshot): Observable> { diff --git a/ui-ngx/src/app/shared/components/cheatsheet.component.ts b/ui-ngx/src/app/shared/components/cheatsheet.component.ts index 39a087506a..54ca7c2f88 100644 --- a/ui-ngx/src/app/shared/components/cheatsheet.component.ts +++ b/ui-ngx/src/app/shared/components/cheatsheet.component.ts @@ -16,6 +16,8 @@ import { Component, ElementRef, Input, OnDestroy, OnInit } from '@angular/core'; import { Hotkey, HotkeysService } from 'angular2-hotkeys'; +import { MousetrapInstance } from 'mousetrap'; +import * as Mousetrap from 'mousetrap'; @Component({ selector : 'tb-hotkeys-cheatsheet', diff --git a/ui-ngx/src/app/shared/components/fab-toolbar.component.scss b/ui-ngx/src/app/shared/components/fab-toolbar.component.scss index edb3ff793e..12e66fd003 100644 --- a/ui-ngx/src/app/shared/components/fab-toolbar.component.scss +++ b/ui-ngx/src/app/shared/components/fab-toolbar.component.scss @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@use "sass:math"; + $font-size: 10px !default; @function rem($multiplier) { @return $multiplier * $font-size; @@ -47,10 +50,10 @@ $swift-ease-in: all $swift-ease-in-duration $swift-ease-in-timing-function !defa } @mixin fab-all-positions() { - @include fab-position(bottom-right, auto, ($button-fab-width - $button-fab-padding)/2, ($button-fab-height - $button-fab-padding)/2, auto); - @include fab-position(bottom-left, auto, auto, ($button-fab-height - $button-fab-padding)/2, ($button-fab-width - $button-fab-padding)/2); - @include fab-position(top-right, ($button-fab-height - $button-fab-padding)/2, ($button-fab-width - $button-fab-padding)/2, auto, auto); - @include fab-position(top-left, ($button-fab-height - $button-fab-padding)/2, auto, auto, ($button-fab-width - $button-fab-padding)/2); + @include fab-position(bottom-right, auto, math.div(($button-fab-width - $button-fab-padding), 2), math.div(($button-fab-height - $button-fab-padding), 2), auto); + @include fab-position(bottom-left, auto, auto, math.div(($button-fab-height - $button-fab-padding), 2), math.div(($button-fab-width - $button-fab-padding), 2)); + @include fab-position(top-right, math.div(($button-fab-height - $button-fab-padding), 2), math.div(($button-fab-width - $button-fab-padding), 2), auto, auto); + @include fab-position(top-left, math.div(($button-fab-height - $button-fab-padding), 2), auto, auto, math.div(($button-fab-width - $button-fab-padding), 2)); } mat-fab-toolbar { @@ -175,7 +178,7 @@ mat-fab-toolbar { mat-toolbar { .mat-fab-action-item { transition: $swift-ease-in; - transition-duration: $swift-ease-in-duration / 2; + transition-duration: math.div($swift-ease-in-duration, 2); } } &.mat-is-open { diff --git a/ui-ngx/src/app/shared/components/hotkeys.directive.ts b/ui-ngx/src/app/shared/components/hotkeys.directive.ts index 37723a8407..d1419c0ee4 100644 --- a/ui-ngx/src/app/shared/components/hotkeys.directive.ts +++ b/ui-ngx/src/app/shared/components/hotkeys.directive.ts @@ -16,7 +16,8 @@ import { Directive, ElementRef, Input, OnDestroy, OnInit } from '@angular/core'; import { Hotkey } from 'angular2-hotkeys'; -import 'mousetrap'; +import { MousetrapInstance } from 'mousetrap'; +import * as Mousetrap from 'mousetrap'; import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component'; @Directive({ diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx index eef3fe5c84..f9fe16bd9c 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx @@ -14,12 +14,12 @@ * limitations under the License. */ import * as React from 'react'; -import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; +import { createTheme, ThemeProvider } from '@material-ui/core/styles'; import thingsboardTheme from './styles/thingsboardTheme'; import ThingsboardSchemaForm from './json-form-schema-form'; import { JsonFormProps } from './json-form.models'; -const tbTheme = createMuiTheme(thingsboardTheme); +const tbTheme = createTheme(thingsboardTheme); class ReactSchemaForm extends React.Component { diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form.scss b/ui-ngx/src/app/shared/components/json-form/react/json-form.scss index fb33d2afc0..67f737953a 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form.scss +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form.scss @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "~compass-sass-mixins/lib/compass"; $swift-ease-out-duration: .4s !default; $swift-ease-out-timing-function: cubic-bezier(.25, .8, .25, 1) !default; diff --git a/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts b/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts index ef4ba9fc84..1084a7c4c2 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts +++ b/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts @@ -31,7 +31,7 @@ */ import indigo from '@material-ui/core/colors/indigo'; import deeepOrange from '@material-ui/core/colors/deepOrange'; -import { ThemeOptions } from '@material-ui/core/styles/createMuiTheme'; +import { ThemeOptions } from '@material-ui/core/styles'; import { PaletteOptions } from '@material-ui/core/styles/createPalette'; import { mergeDeep } from '@core/utils'; diff --git a/ui-ngx/src/app/shared/components/nav-tree.component.ts b/ui-ngx/src/app/shared/components/nav-tree.component.ts index 7de7a8902f..1be3ba8bc8 100644 --- a/ui-ngx/src/app/shared/components/nav-tree.component.ts +++ b/ui-ngx/src/app/shared/components/nav-tree.component.ts @@ -76,19 +76,19 @@ export class NavTreeComponent implements OnInit { } @Input() - private loadNodes: LoadNodesCallback; + loadNodes: LoadNodesCallback; @Input() - private searchCallback: NodeSearchCallback; + searchCallback: NodeSearchCallback; @Input() - private onNodeSelected: NodeSelectedCallback; + onNodeSelected: NodeSelectedCallback; @Input() - private onNodesInserted: NodesInsertedCallback; + onNodesInserted: NodesInsertedCallback; @Input() - private editCallbacks: NavTreeEditCallbacks; + editCallbacks: NavTreeEditCallbacks; private treeElement: JSTree; diff --git a/ui-ngx/src/app/shared/components/popover.component.scss b/ui-ngx/src/app/shared/components/popover.component.scss index 48b7eb7d27..6a9c289fa1 100644 --- a/ui-ngx/src/app/shared/components/popover.component.scss +++ b/ui-ngx/src/app/shared/components/popover.component.scss @@ -124,7 +124,7 @@ $box-shadow-base: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, height: sqrt($popover-arrow-width * $popover-arrow-width * 2) + px; background: transparent; border-style: solid; - border-width: (sqrt($popover-arrow-width * $popover-arrow-width * 2) / 2) + px; + border-width: (sqrt($popover-arrow-width * $popover-arrow-width * 2) * 0.5) + px; transform: rotate(45deg); z-index: 10; } diff --git a/ui-ngx/src/app/shared/components/tokens.ts b/ui-ngx/src/app/shared/components/tokens.ts index 8171d52839..205357b6f9 100644 --- a/ui-ngx/src/app/shared/components/tokens.ts +++ b/ui-ngx/src/app/shared/components/tokens.ts @@ -21,4 +21,4 @@ export const HELP_MARKDOWN_COMPONENT_TOKEN: InjectionToken> = new InjectionToken>('HELP_MARKDOWN_COMPONENT_TOKEN'); export const SHARED_MODULE_TOKEN: InjectionToken> = - new InjectionToken>('HELP_MARKDOWN_COMPONENT_TOKEN'); + new InjectionToken>('SHARED_MODULE_TOKEN'); diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 03b38345ca..b30ed084ab 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -15,6 +15,7 @@ /// import { InjectionToken } from '@angular/core'; +import { IModulesMap } from '@modules/common/modules-map.models'; export const Constants = { serverErrorCode: { @@ -244,4 +245,4 @@ export const contentTypesMap = new Map( export const customTranslationsPrefix = 'custom.'; export const i18nPrefix = 'i18n'; -export const MODULES_MAP = new InjectionToken<{[key: string]: any}>('ModulesMap'); +export const MODULES_MAP = new InjectionToken('ModulesMap'); diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 90b80393dd..50ffdafa65 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -132,7 +132,7 @@ import { NavTreeComponent } from '@shared/components/nav-tree.component'; import { LedLightComponent } from '@shared/components/led-light.component'; import { TbJsonToStringDirective } from '@shared/components/directives/tb-json-to-string.directive'; import { JsonObjectEditDialogComponent } from '@shared/components/dialog/json-object-edit-dialog.component'; -import { HistorySelectorComponent } from './components/time/history-selector/history-selector.component'; +import { HistorySelectorComponent } from '@shared/components/time/history-selector/history-selector.component'; import { EntityGatewaySelectComponent } from '@shared/components/entity/entity-gateway-select.component'; import { DndModule } from 'ngx-drag-drop'; import { QueueTypeListComponent } from '@shared/components/queue/queue-type-list.component'; @@ -155,7 +155,7 @@ import { MarkedOptionsService } from '@shared/components/marked-options.service' import { TbPopoverService } from '@shared/components/popover.service'; import { HELP_MARKDOWN_COMPONENT_TOKEN, SHARED_MODULE_TOKEN } from '@shared/components/tokens'; import { TbMarkdownComponent } from '@shared/components/markdown.component'; -import { ProtobufContentComponent } from './components/protobuf-content.component'; +import { ProtobufContentComponent } from '@shared/components/protobuf-content.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; diff --git a/ui-ngx/src/scss/animations.scss b/ui-ngx/src/scss/animations.scss index 2d8bf3469e..5a0fcff2b5 100644 --- a/ui-ngx/src/scss/animations.scss +++ b/ui-ngx/src/scss/animations.scss @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "~compass-sass-mixins/lib/animate"; @keyframes tbMoveFromTopFade { from { diff --git a/ui-ngx/src/scss/mixins.scss b/ui-ngx/src/scss/mixins.scss index 2d2495b998..cb3e24a9d7 100644 --- a/ui-ngx/src/scss/mixins.scss +++ b/ui-ngx/src/scss/mixins.scss @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@use "sass:math"; + @mixin tb-mat-icon-size($size) { width: #{$size}px; min-width: #{$size}px; @@ -51,7 +53,7 @@ $x1: $x0; @for $i from 1 through 10 { - $x1: $x0 - ($x0 * $x0 - abs($r)) / (2 * $x0); + $x1: $x0 - math.div($x0 * $x0 - abs($r), 2 * $x0); $x0: $x1; } diff --git a/ui-ngx/src/theme.scss b/ui-ngx/src/theme.scss index fdad632bee..6821a0706b 100644 --- a/ui-ngx/src/theme.scss +++ b/ui-ngx/src/theme.scss @@ -158,17 +158,20 @@ $tb-dark-theme: get-tb-dark-theme( } &.mat-primary { .mat-fab-toolbar-background { - @include _mat-toolbar-color($primary); + background: mat.get-color-from-palette($primary); + color: mat.get-color-from-palette($primary, default-contrast); } } &.mat-accent { .mat-fab-toolbar-background { - @include _mat-toolbar-color($accent); + background: mat.get-color-from-palette($accent); + color: mat.get-color-from-palette($accent, default-contrast); } } &.mat-warn { .mat-fab-toolbar-background { - @include _mat-toolbar-color($warn); + background: mat.get-color-from-palette($warn); + color: mat.get-color-from-palette($warn, default-contrast); } } } diff --git a/ui-ngx/src/tsconfig.app.json b/ui-ngx/src/tsconfig.app.json index e73cce9a21..fb8ea9b284 100644 --- a/ui-ngx/src/tsconfig.app.json +++ b/ui-ngx/src/tsconfig.app.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "../out-tsc/app", "types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", - "react", "react-dom", "jstree", "raphael", "canvas-gauges"] + "react", "react-dom", "jstree", "raphael", "canvas-gauges", "systemjs"] }, "angularCompilerOptions": { "fullTemplateTypeCheck": true diff --git a/ui-ngx/tsconfig.json b/ui-ngx/tsconfig.json index 131a93b826..2243eae689 100644 --- a/ui-ngx/tsconfig.json +++ b/ui-ngx/tsconfig.json @@ -3,15 +3,18 @@ "compilerOptions": { "baseUrl": "./", "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, "sourceMap": true, "declaration": false, - "module": "es2020", + "downlevelIteration": true, + "experimentalDecorators": true, "moduleResolution": "node", + "importHelpers": true, + "target": "es2017", + "module": "es2020", "emitDecoratorMetadata": true, - "experimentalDecorators": true, "allowSyntheticDefaultImports": true, - "importHelpers": true, - "target": "es5", "jsx": "react", "typeRoots": [ "node_modules/@types", @@ -52,9 +55,14 @@ ] }, "lib": [ - "es2018", - "es2019", + "es2020", "dom" ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": false } } diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 9aae7fabc0..ba822f9116 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -10,28 +10,20 @@ "@jridgewell/resolve-uri" "1.0.0" sourcemap-codec "1.4.8" -"@angular-builders/custom-webpack@~11.1.1": - version "11.1.1" - resolved "https://registry.yarnpkg.com/@angular-builders/custom-webpack/-/custom-webpack-11.1.1.tgz#5ef535f5c51cb2f5a27f53fcfab54176cd1d14d4" - integrity sha512-9l2yC9+QMwWj9IEsOpQtMIBcH87UMZdoR2+8DbIt53ypst/8aVMhMsKmR5n33wRkLlIJ6/ubyXldQymIHzoF1g== - dependencies: - "@angular-devkit/architect" ">=0.1100.0 < 0.1200.0" - "@angular-devkit/build-angular" ">=0.1100.0 < 0.1200.0" - "@angular-devkit/core" "^11.0.0" +"@angular-builders/custom-webpack@~12.1.3": + version "12.1.3" + resolved "https://registry.yarnpkg.com/@angular-builders/custom-webpack/-/custom-webpack-12.1.3.tgz#3eda78f573dc6d8b5278bb2d0c20937a75dec0cc" + integrity sha512-CzOkwYnO2Xs+z4kMeJkUALeRjVE69SlrqbEsv2Tao5PsBmFCyT5EEVoSvwOuaxZmajuGaXtz7yBIeK2hYp25/A== + dependencies: + "@angular-devkit/architect" ">=0.1200.0 < 0.1300.0" + "@angular-devkit/build-angular" "^12.0.0" + "@angular-devkit/core" "^12.0.0" lodash "^4.17.15" - ts-node "^9.0.0" + ts-node "^10.0.0" tsconfig-paths "^3.9.0" webpack-merge "^5.7.3" -"@angular-devkit/architect@0.1102.13", "@angular-devkit/architect@>=0.1100.0 < 0.1200.0": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1102.13.tgz#0f6b9d38cb8cda928b24404278f227fe8f169fc1" - integrity sha512-v44YF54DQnxwggZKUVCB2WtgfqMW8VG5AtE+nO0RgEtgnOC3e4bB7dZ/n+2Am0LCauYx45ufQDlIespeX09XgA== - dependencies: - "@angular-devkit/core" "11.2.13" - rxjs "6.6.3" - -"@angular-devkit/architect@0.1202.13": +"@angular-devkit/architect@0.1202.13", "@angular-devkit/architect@>=0.1200.0 < 0.1300.0": version "0.1202.13" resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1202.13.tgz#b9b883d62f628a6b31ce071da91e268f61da00ef" integrity sha512-LXgiidXwBgyWPqqWK4xR1/kCPQTMTzG5w+s7+LvENUZwbcdl6CKrOMjfgjo6WPr6yeq+WWQvPCD4pZ6nXRTm7A== @@ -39,86 +31,7 @@ "@angular-devkit/core" "12.2.13" rxjs "6.6.7" -"@angular-devkit/build-angular@>=0.1100.0 < 0.1200.0": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.1102.13.tgz#3d7bac8d471c6f2b7067236151cc5018b2ad1a51" - integrity sha512-1ezVautOtfl16pOT3p7Z9IPd7vSyy6lZ+HZWqMK1AmUjNhsEA2WeuC/XznGatC3K+9IcfV+eSm6cP0iuLyETzw== - dependencies: - "@angular-devkit/architect" "0.1102.13" - "@angular-devkit/build-optimizer" "0.1102.13" - "@angular-devkit/build-webpack" "0.1102.13" - "@angular-devkit/core" "11.2.13" - "@babel/core" "7.12.10" - "@babel/generator" "7.12.11" - "@babel/plugin-transform-async-to-generator" "7.12.1" - "@babel/plugin-transform-runtime" "7.12.10" - "@babel/preset-env" "7.12.11" - "@babel/runtime" "7.12.5" - "@babel/template" "7.12.7" - "@discoveryjs/json-ext" "0.5.2" - "@jsdevtools/coverage-istanbul-loader" "3.0.5" - "@ngtools/webpack" "11.2.13" - ansi-colors "4.1.1" - autoprefixer "10.2.4" - babel-loader "8.2.2" - browserslist "^4.9.1" - cacache "15.0.5" - caniuse-lite "^1.0.30001032" - circular-dependency-plugin "5.2.2" - copy-webpack-plugin "6.3.2" - core-js "3.8.3" - critters "0.0.7" - css-loader "5.0.1" - cssnano "5.0.2" - file-loader "6.2.0" - find-cache-dir "3.3.1" - glob "7.1.6" - https-proxy-agent "5.0.0" - inquirer "7.3.3" - jest-worker "26.6.2" - karma-source-map-support "1.4.0" - less "4.1.1" - less-loader "7.3.0" - license-webpack-plugin "2.3.11" - loader-utils "2.0.0" - mini-css-extract-plugin "1.3.5" - minimatch "3.0.4" - open "7.4.0" - ora "5.3.0" - parse5-html-rewriting-stream "6.0.1" - pnp-webpack-plugin "1.6.4" - postcss "8.2.14" - postcss-import "14.0.0" - postcss-loader "4.2.0" - raw-loader "4.0.2" - regenerator-runtime "0.13.7" - resolve-url-loader "4.0.0" - rimraf "3.0.2" - rollup "2.38.4" - rxjs "6.6.3" - sass "1.32.6" - sass-loader "10.1.1" - semver "7.3.4" - source-map "0.7.3" - source-map-loader "1.1.3" - source-map-support "0.5.19" - speed-measure-webpack-plugin "1.4.2" - style-loader "2.0.0" - stylus "0.54.8" - stylus-loader "4.3.3" - terser "5.5.1" - terser-webpack-plugin "4.2.3" - text-table "0.2.0" - tree-kill "1.2.2" - webpack "4.44.2" - webpack-dev-middleware "3.7.2" - webpack-dev-server "3.11.2" - webpack-merge "5.7.3" - webpack-sources "2.2.0" - webpack-subresource-integrity "1.5.2" - worker-plugin "5.0.0" - -"@angular-devkit/build-angular@^12.2.13": +"@angular-devkit/build-angular@^12.0.0", "@angular-devkit/build-angular@^12.2.13": version "12.2.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-12.2.13.tgz#f5564d3ec9db132956473bb904bb3590482f5b36" integrity sha512-iJ1P/RZ1hk2n/HtEqB5ohXvHa+Hf0BXShYskSGrn6/klcTb0eJTCREsFxHk7mNEmRIGPWkjbLAslqpPgwiagXg== @@ -195,17 +108,6 @@ optionalDependencies: esbuild "0.13.8" -"@angular-devkit/build-optimizer@0.1102.13": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1102.13.tgz#5c60fa88db41f22f296f1ee628f4c6abe90dac95" - integrity sha512-OvTsUVe5cC4oKym1pohVzkn50OLnjK/SuOnMgeWceMDkqmzJEdJqhG1SfnXv+MJiuUDlhyUVbbnFwkj5Y0fXYA== - dependencies: - loader-utils "2.0.0" - source-map "0.7.3" - tslib "2.1.0" - typescript "4.1.5" - webpack-sources "2.2.0" - "@angular-devkit/build-optimizer@0.1202.13": version "0.1202.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1202.13.tgz#7f0b13368cc2a08b1f4789ab1296a1609f5049ea" @@ -215,15 +117,6 @@ tslib "2.3.0" typescript "4.3.5" -"@angular-devkit/build-webpack@0.1102.13": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1102.13.tgz#d7d552500713278cc3ed28c3cc669f31b4f285a6" - integrity sha512-5KMq7jUtk5GOuErR6psG8ypyfHL/sITfpgyRXcsqJEqLEbb5MPmaR9gBjz6TSQGUH2/jNiJjdd82h8ckWxfN8g== - dependencies: - "@angular-devkit/architect" "0.1102.13" - "@angular-devkit/core" "11.2.13" - rxjs "6.6.3" - "@angular-devkit/build-webpack@0.1202.13": version "0.1202.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1202.13.tgz#875f9f9677bb10056b52230965dc2f00bd3089dd" @@ -232,18 +125,7 @@ "@angular-devkit/architect" "0.1202.13" rxjs "6.6.7" -"@angular-devkit/core@11.2.13", "@angular-devkit/core@^11.0.0": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-11.2.13.tgz#7829862132555a52009d0af9671b06ffdf9200f1" - integrity sha512-GL97DZXeQCecqZmaIeMfG/XtHv6e7FM+uygMePNF9yn4cml32bSp4P5oRjDMgj7iFl6GIU81n8TstTMmFbt85w== - dependencies: - ajv "6.12.6" - fast-json-stable-stringify "2.1.0" - magic-string "0.25.7" - rxjs "6.6.3" - source-map "0.7.3" - -"@angular-devkit/core@12.2.13": +"@angular-devkit/core@12.2.13", "@angular-devkit/core@^12.0.0": version "12.2.13" resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-12.2.13.tgz#db3929d1bfce71010b37fb7c4e6c33ef80a4f35f" integrity sha512-9csMF0p+lTvlWnutxxTZ/+pDRMIbXk/TV4MGLbcqUPPfeG3dCRwErns73xLuMTwp9qO/KCLkFqNaM6cGOoqsDA== @@ -265,9 +147,9 @@ rxjs "6.6.7" "@angular/animations@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-12.2.13.tgz#909b79c56a85bb31c0605ed419850340b5580be9" - integrity sha512-qpdmvu+nxsKnimJ3Hc1joNuzK7xXYyE+VtNMk4K77Ao/9+5C/juGMce85DhqZCcu1xraZ3YYIrzYmL/GgdUK4g== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-12.2.14.tgz#5b74f17f5d58993d92511749fa5ceaf2de6c1495" + integrity sha512-1BR5u32auVePvXNNP96DB2008V+Ku0OGqeZQl2h4XA9xzES/Zk5WllIJZXqRmWMRBVARfXsfb0RdMty9gcaVjA== dependencies: tslib "^2.2.0" @@ -306,16 +188,16 @@ uuid "8.3.2" "@angular/common@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-12.2.13.tgz#fe52ffae8668c1dec41b26cdc3a749101399e1fe" - integrity sha512-I1t/jl9ojCwTJKT7PKHnk23D+vMHTHS/9qZ2nndCjzGusMK8029nn8l3tHAkwefvxZWSaLAk1MgsVcP+rHQNsQ== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-12.2.14.tgz#0cd0d75be8052e8be76966e494f245dc595afe10" + integrity sha512-ffYUYdwZETmFJw0AcWY30WsaWBhJxj/zSmFXWjgEGEGZH56zwbbNwfMZOYZ1jz4haAVxGu+TdXsOl2yMGzN7jQ== dependencies: tslib "^2.2.0" "@angular/compiler-cli@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-12.2.13.tgz#3ce463263e80a861e14af2ed3ba81598060e3ce0" - integrity sha512-qmnmihl3SCRooj/mCsNIZLtnQ6qbx1/L6aMIEQosPvQhMeGMt8GCYvQPE8IZ+sahv7fih95HCWNa9TeLpOylug== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-12.2.14.tgz#fdaca73c6941b1231196d980ac8ef02c07ccf36d" + integrity sha512-EktEOF2xnuMsUyanXjZw3hyn7w97NX9h8LJ3O9l27secbjYXhyrao5bmrMILdDTEJNeZSC/OuCga1pvdaJTYmg== dependencies: "@babel/core" "^7.8.6" "@babel/types" "^7.8.6" @@ -338,9 +220,9 @@ integrity sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ== "@angular/compiler@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-12.2.13.tgz#7eef6fdb81b9de6fd0e2cdda2ad8a084c1d9535b" - integrity sha512-L0saTTJJtxldjhaGIL6b1BCfodPOEz4Wrev3pEUK5UcODooj5HLiE/aO6jiNb8M4XTbdqByKyqvZyWzGHeexVQ== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-12.2.14.tgz#360940f5e505a00892b46dd28ca69b9a37bdf6af" + integrity sha512-dwmZi+n66IUzRFlGWu9mjXq170ZEsaDvlNLZzaPgs6vZTa4Kt7PWvIF/Y7TMvnVv/uqNG6kOhfmOkf6rfz1Gjg== dependencies: tslib "^2.2.0" @@ -350,9 +232,9 @@ integrity sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w== "@angular/core@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-12.2.13.tgz#fc40acbdcee5c5878bd249ddc0d643be724076c3" - integrity sha512-tZ5nAnmOi418JDaJIFiiP9z2JrluMJZvUvXO4QDUs52BXaL2yuP7MJ2LczWOVJXrBLZXeZGfjDjZmaFPA24grg== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-12.2.14.tgz#6ae14e63a88c534cd48d03184cbb084ec031bad1" + integrity sha512-dlVk7yqUHL2R/eCmM8LsWuxhEBfzg0y1zHt0UqCuFwlCoiw+IG4HFy4OlZEUw9NUEZJSv0aDv3sWqxLkvK5vvg== dependencies: tslib "^2.2.0" @@ -364,16 +246,16 @@ tslib "^2.1.0" "@angular/forms@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-12.2.13.tgz#4de90e88991c274b5d5e3ab0300267e161ba78f2" - integrity sha512-wa7I5R8sck2q+VWNL262GJTVxtpEHMys8Bt6oE+lyHB5zlZAgOXwAb8GE4XVwuc+BZU1Gvrocn21P/8KvDY1uw== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-12.2.14.tgz#cb88c1c1432e3fc75d6832dfa4e97c9667396586" + integrity sha512-/9/gSJUBXVRVdRnzgJnALAQZYJATuGDMkFC9ms9DEMG4PMAhe9x4if1lJjN6noz5RAom3qNuVBNWaYAPUxlcBQ== dependencies: tslib "^2.2.0" "@angular/language-service@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.2.13.tgz#326045a328f8a962287037d7a85be8120074421c" - integrity sha512-jb9s3IJuWNKTRcM90NOwvMfiy85nnKfTxxLVn8/QFMO6+Ps/hsVZNp+W/TmAEDvCkon+9q0O4hwa4MY1m/Dlkw== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.2.14.tgz#4f0afc2fe7fed6838c640a0da8658767c8372e1d" + integrity sha512-DSEhiBM077z7Gx99KQOQmtJSIdLT39GAAJ30nHO3IuBT7n5Wi+K6b/eO3mOvXrzcQ8K5WFxJboJ2GJRlPXzlwQ== "@angular/material@^12.2.13": version "12.2.13" @@ -383,31 +265,26 @@ tslib "^2.2.0" "@angular/platform-browser-dynamic@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-12.2.13.tgz#9ee6309f511da419d5d80a1a8279adc806e92f04" - integrity sha512-a7y7R3vOXhMAk9uQWK5/23DefahuF0UYJSFM/wKeVo5zR+qOCVCTfafkJMcWbuZWTrSDbVafJ1xbcWnu3+TkCg== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-12.2.14.tgz#202fd89ba7f758ca998ee5b6498d4a834472f664" + integrity sha512-0NPF7mS91Tct8rBmOLZPmnLSuS4kbLHXo6eTgrg80OC0vlzBiQwGDVW4X3KncCoX9CpevaGJCdSMc+uPNsFOUQ== dependencies: tslib "^2.2.0" "@angular/platform-browser@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-12.2.13.tgz#769fb148b2128663d6b405d2a41023f2cdaa1c95" - integrity sha512-Ua8m2GtG2msqz/Mr/MK7s8RXud554x8cup2THVAwetyTaY5th/1LOZX0hhDIhfsxBCLHnC53LRhMbSsI0cikOg== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-12.2.14.tgz#2c00d5f341827dc1de4ade98abcf329f0824790c" + integrity sha512-fWcE2rnJ3ZCISa1oPfsIDV7FBZBoLFEdDuMXAiDYqDPKvF/E5U5nHrS+K4SlLAi094bMobtTOReNWl/Ienniyw== dependencies: tslib "^2.2.0" "@angular/router@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-12.2.13.tgz#e5b939a9675f9d4834fee3e75eb8d040ef63b3b5" - integrity sha512-HZL/Pzp6I7fQiMLrzfEzhnqhgNcGcFjBgMMOoLp5IA1IV26rp1NU6zYJzPrXtopBx7XLl8BECehAwFqrJsu/PQ== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-12.2.14.tgz#93f965d2e50bb4ecf5a17ff5217cef266fb67c06" + integrity sha512-yP5grSnqBvc4vNhtYdcxDgDYIebUKs5f0xyFkUJM5030UnQ0CV45tBsSxHMkQbPZucIfOuxpRy8xy5+4GizuwQ== dependencies: tslib "^2.2.0" -"@ant-design/css-animation@^1.7.2": - version "1.7.3" - resolved "https://registry.yarnpkg.com/@ant-design/css-animation/-/css-animation-1.7.3.tgz#60a1c970014e86b28f940510d69e503e428f1136" - integrity sha512-LrX0OGZtW+W6iLnTAqnTaoIsRelYeuLZWsrmBJFUXDALQphPsN8cE5DCsmoSlL0QYb94BQxINiuS70Ar/8BNgA== - "@assemblyscript/loader@^0.10.1": version "0.10.1" resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06" @@ -420,58 +297,18 @@ dependencies: tslib "^2.0.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" - integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== - dependencies: - "@babel/highlight" "^7.12.13" - -"@babel/code-frame@^7.14.5", "@babel/code-frame@^7.16.0": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== dependencies: "@babel/highlight" "^7.16.0" -"@babel/compat-data@^7.12.7", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" - integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== - "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.16.0": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== -"@babel/core@7.12.10": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" - integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.10" - "@babel/helper-module-transforms" "^7.12.1" - "@babel/helpers" "^7.12.5" - "@babel/parser" "^7.12.10" - "@babel/template" "^7.12.7" - "@babel/traverse" "^7.12.10" - "@babel/types" "^7.12.10" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - semver "^5.4.1" - source-map "^0.5.0" - "@babel/core@7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.8.tgz#20cdf7c84b5d86d83fac8710a8bc605a7ba3f010" @@ -493,42 +330,20 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/core@^7.7.5": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" - integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.6" - "@babel/helper-module-transforms" "^7.11.0" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.5" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.5" - "@babel/types" "^7.11.5" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.8.6": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.3.tgz#5395e30405f0776067fbd9cf0884f15bfb770a38" - integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.14.3" - "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-module-transforms" "^7.14.2" - "@babel/helpers" "^7.14.0" - "@babel/parser" "^7.14.3" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.2" +"@babel/core@^7.7.5", "@babel/core@^7.8.6": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4" + integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helpers" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -536,15 +351,6 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af" - integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA== - dependencies: - "@babel/types" "^7.12.11" - jsesc "^2.5.1" - source-map "^0.5.0" - "@babel/generator@7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.8.tgz#bf86fd6af96cf3b74395a8ca409515f89423e070" @@ -554,24 +360,6 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.11.5", "@babel/generator@^7.11.6": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" - integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA== - dependencies: - "@babel/types" "^7.11.5" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/generator@^7.12.10", "@babel/generator@^7.14.2", "@babel/generator@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.3.tgz#0c2652d91f7bddab7cccc6ba8157e4f40dcedb91" - integrity sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA== - dependencies: - "@babel/types" "^7.14.2" - jsesc "^2.5.1" - source-map "^0.5.0" - "@babel/generator@^7.14.8", "@babel/generator@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" @@ -588,20 +376,6 @@ dependencies: "@babel/types" "^7.14.5" -"@babel/helper-annotate-as-pure@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" - integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-annotate-as-pure@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab" - integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-annotate-as-pure@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" @@ -609,14 +383,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc" - integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.12.13" - "@babel/types" "^7.12.13" - "@babel/helper-builder-binary-assignment-operator-visitor@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz#f1a686b92da794020c26582eb852e9accd0d7882" @@ -625,16 +391,6 @@ "@babel/helper-explode-assignable-expression" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-compilation-targets@^7.12.5", "@babel/helper-compilation-targets@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" - integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== - dependencies: - "@babel/compat-data" "^7.13.15" - "@babel/helper-validator-option" "^7.12.17" - browserslist "^4.14.5" - semver "^6.3.0" - "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" @@ -645,18 +401,6 @@ browserslist "^4.17.5" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.13.0": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.3.tgz#832111bcf4f57ca57a4c5b1a000fc125abc6554a" - integrity sha512-BnEfi5+6J2Lte9LeiL6TxLWdIlEv9Woacc1qXzXBgbikcOzMRM2Oya5XGg/f/ngotv1ej2A/b+3iJH8wbS1+lQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-member-expression-to-functions" "^7.13.12" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/helper-replace-supers" "^7.14.3" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-create-class-features-plugin@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" @@ -669,23 +413,6 @@ "@babel/helper-replace-supers" "^7.16.0" "@babel/helper-split-export-declaration" "^7.16.0" -"@babel/helper-create-regexp-features-plugin@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" - integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-regex" "^7.10.4" - regexpu-core "^4.7.0" - -"@babel/helper-create-regexp-features-plugin@^7.12.13": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.3.tgz#149aa6d78c016e318c43e2409a0ae9c136a86688" - integrity sha512-JIB2+XJrb7v3zceV2XzDhGIB902CmKGSpSl4q2C6agU9SNLG/2V1RtFRGPG1Ajh9STj3+q6zJMOC+N/pp2P9DA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - regexpu-core "^4.7.1" - "@babel/helper-create-regexp-features-plugin@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" @@ -708,13 +435,6 @@ resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-explode-assignable-expression@^7.12.13": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f" - integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA== - dependencies: - "@babel/types" "^7.13.0" - "@babel/helper-explode-assignable-expression@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" @@ -722,24 +442,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" - integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== - dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz#397688b590760b6ef7725b5f0860c82427ebaac2" - integrity sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ== - dependencies: - "@babel/helper-get-function-arity" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/types" "^7.14.2" - "@babel/helper-function-name@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" @@ -749,20 +451,6 @@ "@babel/template" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-get-function-arity@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" - integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-get-function-arity@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" - integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-get-function-arity@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" @@ -770,14 +458,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-hoist-variables@^7.13.0": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.16.tgz#1b1651249e94b51f8f0d33439843e33e39775b30" - integrity sha512-1eMtTrXtrwscjcAeO4BVK+vvkxaLJSPFz1w1KLawz6HLNi9bPFGBNwwDyVfiu1Tv/vRRFYfoGaKhmAQPGPn5Wg== - dependencies: - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.16" - "@babel/helper-hoist-variables@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" @@ -785,20 +465,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-member-expression-to-functions@^7.10.4": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" - integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-member-expression-to-functions@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" - integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== - dependencies: - "@babel/types" "^7.13.12" - "@babel/helper-member-expression-to-functions@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" @@ -806,54 +472,13 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.12.5", "@babel/helper-module-imports@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" - integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== - dependencies: - "@babel/types" "^7.13.12" - -"@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.16.0": +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== dependencies: "@babel/types" "^7.16.0" -"@babel/helper-module-transforms@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" - integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/template" "^7.10.4" - "@babel/types" "^7.11.0" - lodash "^4.17.19" - -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.14.0", "@babel/helper-module-transforms@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz#ac1cc30ee47b945e3e0c4db12fa0c5389509dfe5" - integrity sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA== - dependencies: - "@babel/helper-module-imports" "^7.13.12" - "@babel/helper-replace-supers" "^7.13.12" - "@babel/helper-simple-access" "^7.13.12" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-validator-identifier" "^7.14.0" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.2" - "@babel/helper-module-transforms@^7.14.8", "@babel/helper-module-transforms@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" @@ -868,20 +493,6 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-optimise-call-expression@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" - integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-optimise-call-expression@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" - integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-optimise-call-expression@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" @@ -889,37 +500,11 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== - -"@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" - integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== - -"@babel/helper-plugin-utils@^7.14.5": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== -"@babel/helper-regex@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" - integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== - dependencies: - lodash "^4.17.19" - -"@babel/helper-remap-async-to-generator@^7.12.1", "@babel/helper-remap-async-to-generator@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209" - integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-wrap-function" "^7.13.0" - "@babel/types" "^7.13.0" - "@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.16.0", "@babel/helper-remap-async-to-generator@^7.16.4": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz#5d7902f61349ff6b963e07f06a389ce139fbfe6e" @@ -929,26 +514,6 @@ "@babel/helper-wrap-function" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-replace-supers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" - integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.12", "@babel/helper-replace-supers@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.3.tgz#ca17b318b859d107f0e9b722d58cf12d94436600" - integrity sha512-Rlh8qEWZSTfdz+tgNV/N4gz1a0TMNwCUcENhMjHTHKp3LseYH5Jha0NSlyTQWMnjbYcwFt+bqAMqSLHVXkQ6UA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.13.12" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.2" - "@babel/helper-replace-supers@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" @@ -959,21 +524,6 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-simple-access@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" - integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== - dependencies: - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-simple-access@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" - integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== - dependencies: - "@babel/types" "^7.13.12" - "@babel/helper-simple-access@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" @@ -981,13 +531,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-skip-transparent-expression-wrappers@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" - integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA== - dependencies: - "@babel/types" "^7.12.1" - "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" @@ -995,20 +538,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-split-export-declaration@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" - integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-split-export-declaration@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" - integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-split-export-declaration@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" @@ -1016,41 +545,16 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-validator-identifier@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" - integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== - -"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" - integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== - "@babel/helper-validator-identifier@^7.15.7": version "7.15.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== -"@babel/helper-validator-option@^7.12.11", "@babel/helper-validator-option@^7.12.17": - version "7.12.17" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" - integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== - "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== -"@babel/helper-wrap-function@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4" - integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA== - dependencies: - "@babel/helper-function-name" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" - "@babel/helper-wrap-function@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" @@ -1061,25 +565,7 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helpers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" - integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== - dependencies: - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helpers@^7.12.5", "@babel/helpers@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" - integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== - dependencies: - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.14.0" - -"@babel/helpers@^7.14.8": +"@babel/helpers@^7.14.8", "@babel/helpers@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== @@ -1088,24 +574,6 @@ "@babel/traverse" "^7.16.3" "@babel/types" "^7.16.0" -"@babel/highlight@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" - integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/highlight@^7.12.13": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" - integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/highlight@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" @@ -1115,16 +583,6 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.4", "@babel/parser@^7.11.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" - integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== - -"@babel/parser@^7.12.10", "@babel/parser@^7.12.13", "@babel/parser@^7.12.7", "@babel/parser@^7.14.2", "@babel/parser@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.3.tgz#9b530eecb071fd0c93519df25c5ff9f14759f298" - integrity sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ== - "@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" @@ -1148,15 +606,6 @@ "@babel/helper-remap-async-to-generator" "^7.14.5" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-async-generator-functions@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.2.tgz#3a2085abbf5d5f962d480dbc81347385ed62eb1e" - integrity sha512-b1AM4F6fwck4N8ItZ/AtC4FP/cqZqmKRQ4FaTDutwSYyjuhtvsGEMLK4N/ztV/ImP40BjIDyMgBQAeAMsQYVFQ== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-remap-async-to-generator" "^7.13.0" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-proposal-async-generator-functions@^7.14.7": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz#e606eb6015fec6fa5978c940f315eae4e300b081" @@ -1166,14 +615,6 @@ "@babel/helper-remap-async-to-generator" "^7.16.4" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-class-properties@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" - integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-proposal-class-properties@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" @@ -1191,14 +632,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-dynamic-import@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.2.tgz#01ebabd7c381cff231fa43e302939a9de5be9d9f" - integrity sha512-oxVQZIWFh91vuNEMKltqNsKLFWkOIyJc95k2Gv9lWVyDfPUQGSSlbDEgWuJUU1afGE9WwlzpucMZ3yDRHIItkA== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-proposal-dynamic-import@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" @@ -1207,14 +640,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-export-namespace-from@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.2.tgz#62542f94aa9ce8f6dba79eec698af22112253791" - integrity sha512-sRxW3z3Zp3pFfLAgVEvzTFutTXax837oOatUIvSG9o5gRj9mKwm3br1Se5f4QalTQs9x4AzlA/HrCWbQIHASUQ== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-proposal-export-namespace-from@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" @@ -1223,14 +648,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-proposal-json-strings@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.2.tgz#830b4e2426a782e8b2878fbfe2cba85b70cbf98c" - integrity sha512-w2DtsfXBBJddJacXMBhElGEYqCZQqN99Se1qeYn8DVLB33owlrlLftIbMzn5nz1OITfDVknXF433tBrLEAOEjA== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-proposal-json-strings@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" @@ -1239,14 +656,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.2.tgz#222348c080a1678e0e74ea63fe76f275882d1fd7" - integrity sha512-1JAZtUrqYyGsS7IDmFeaem+/LJqujfLZ2weLR9ugB0ufUPjzf8cguyVT1g5im7f7RXxuLq1xUxEzvm68uYRtGg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-proposal-logical-assignment-operators@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" @@ -1255,14 +664,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.2.tgz#425b11dc62fc26939a2ab42cbba680bdf5734546" - integrity sha512-ebR0zU9OvI2N4qiAC38KIAK75KItpIPTpAtd2r4OZmMFeKbKJpUFLYP2EuDut82+BmYi8sz42B+TfTptJ9iG5Q== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" @@ -1271,14 +672,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-proposal-numeric-separator@^7.12.7": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.2.tgz#82b4cc06571143faf50626104b335dd71baa4f9e" - integrity sha512-DcTQY9syxu9BpU3Uo94fjCB3LN9/hgPS8oUL7KrSW3bA2ePrKZZPJcc5y0hoJAM9dft3pGfErtEUvxXQcfLxUg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-proposal-numeric-separator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" @@ -1287,17 +680,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.2.tgz#e17d418f81cc103fedd4ce037e181c8056225abc" - integrity sha512-hBIQFxwZi8GIp934+nj5uV31mqclC1aYDhctDu5khTi9PCCUOczyy0b34W0oE9U/eJXiqQaKyVsmjeagOaSlbw== - dependencies: - "@babel/compat-data" "^7.14.0" - "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.14.2" - "@babel/plugin-proposal-object-rest-spread@^7.14.7": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" @@ -1309,14 +691,6 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-transform-parameters" "^7.16.0" -"@babel/plugin-proposal-optional-catch-binding@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.2.tgz#150d4e58e525b16a9a1431bd5326c4eed870d717" - integrity sha512-XtkJsmJtBaUbOxZsNk0Fvrv8eiqgneug0A6aqLFZ4TSkar2L5dSXWcnUKHgmjJt49pyB/6ZHvkr3dPgl9MOWRQ== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-catch-binding@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" @@ -1325,15 +699,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.12.7": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.2.tgz#df8171a8b9c43ebf4c1dabe6311b432d83e1b34e" - integrity sha512-qQByMRPwMZJainfig10BoaDldx/+VDtNcrA7qdNaEOAj6VXud+gfrkA8j4CRAU5HjnWREXqIpSpH30qZX1xivA== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-proposal-optional-chaining@^7.14.5", "@babel/plugin-proposal-optional-chaining@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" @@ -1343,14 +708,6 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-private-methods@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz#04bd4c6d40f6e6bbfa2f57e2d8094bad900ef787" - integrity sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-proposal-private-methods@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" @@ -1369,15 +726,7 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-proposal-unicode-property-regex@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" - integrity sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-proposal-unicode-property-regex@^7.14.5": +"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== @@ -1385,22 +734,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" - integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-async-generators@^7.8.0", "@babel/plugin-syntax-async-generators@^7.8.4": +"@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.1", "@babel/plugin-syntax-class-properties@^7.12.13": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -1414,7 +755,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": +"@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== @@ -1428,7 +769,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": +"@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== @@ -1442,7 +783,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== @@ -1456,21 +797,21 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.8.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": +"@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== @@ -1484,13 +825,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" - integrity sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" @@ -1498,13 +832,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-arrow-functions@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" - integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-arrow-functions@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" @@ -1512,15 +839,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-async-to-generator@7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz#3849a49cc2a22e9743cbd6b52926d30337229af1" - integrity sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A== - dependencies: - "@babel/helper-module-imports" "^7.12.1" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-remap-async-to-generator" "^7.12.1" - "@babel/plugin-transform-async-to-generator@7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" @@ -1530,15 +848,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-remap-async-to-generator" "^7.14.5" -"@babel/plugin-transform-async-to-generator@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f" - integrity sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg== - dependencies: - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-remap-async-to-generator" "^7.13.0" - "@babel/plugin-transform-async-to-generator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" @@ -1548,13 +857,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-remap-async-to-generator" "^7.16.0" -"@babel/plugin-transform-block-scoped-functions@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4" - integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-block-scoped-functions@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" @@ -1562,13 +864,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-block-scoping@^7.12.11": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.2.tgz#761cb12ab5a88d640ad4af4aa81f820e6b5fdf5c" - integrity sha512-neZZcP19NugZZqNwMTH+KoBjx5WyvESPSIOQb4JHpfd+zPfqcH65RMu5xJju5+6q/Y2VzYrleQTr+b6METyyxg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-block-scoping@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" @@ -1576,19 +871,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-classes@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.2.tgz#3f1196c5709f064c252ad056207d87b7aeb2d03d" - integrity sha512-7oafAVcucHquA/VZCsXv/gmuiHeYd64UJyyTYU+MPfNu0KeNlxw06IeENBO8bJjXVbolu+j1MM5aKQtH1OMCNg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-replace-supers" "^7.13.12" - "@babel/helper-split-export-declaration" "^7.12.13" - globals "^11.1.0" - "@babel/plugin-transform-classes@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" @@ -1602,13 +884,6 @@ "@babel/helper-split-export-declaration" "^7.16.0" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed" - integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-computed-properties@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" @@ -1616,13 +891,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-destructuring@^7.12.1": - version "7.13.17" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz#678d96576638c19d5b36b332504d3fd6e06dea27" - integrity sha512-UAUqiLv+uRLO+xuBKKMEpC+t7YRNVRqBsWWq1yKXbBZBje/t3IXCiSinZhjn/DC3qzBfICeYd2EFGEbHsh5RLA== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-destructuring@^7.14.7": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" @@ -1630,15 +898,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-dotall-regex@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad" - integrity sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-transform-dotall-regex@^7.14.5": +"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== @@ -1646,21 +906,6 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" - integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-duplicate-keys@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz#6f06b87a8b803fd928e54b81c258f0a0033904de" - integrity sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-duplicate-keys@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" @@ -1668,14 +913,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-exponentiation-operator@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1" - integrity sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-exponentiation-operator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" @@ -1684,13 +921,6 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-for-of@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062" - integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-for-of@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" @@ -1698,14 +928,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-function-name@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051" - integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ== - dependencies: - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-function-name@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" @@ -1714,13 +936,6 @@ "@babel/helper-function-name" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-literals@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9" - integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-literals@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" @@ -1728,13 +943,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-member-expression-literals@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40" - integrity sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-member-expression-literals@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" @@ -1742,15 +950,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-modules-amd@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.2.tgz#6622806fe1a7c07a1388444222ef9535f2ca17b0" - integrity sha512-hPC6XBswt8P3G2D1tSV2HzdKvkqOpmbyoy+g73JG0qlF/qx2y3KaMmXb1fLrpmWGLZYA0ojCvaHdzFWjlmV+Pw== - dependencies: - "@babel/helper-module-transforms" "^7.14.2" - "@babel/helper-plugin-utils" "^7.13.0" - babel-plugin-dynamic-import-node "^2.3.3" - "@babel/plugin-transform-modules-amd@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" @@ -1760,16 +959,6 @@ "@babel/helper-plugin-utils" "^7.14.5" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.12.1": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" - integrity sha512-EX4QePlsTaRZQmw9BsoPeyh5OCtRGIhwfLquhxGp5e32w+dyL8htOcDwamlitmNFK6xBZYlygjdye9dbd9rUlQ== - dependencies: - "@babel/helper-module-transforms" "^7.14.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-simple-access" "^7.13.12" - babel-plugin-dynamic-import-node "^2.3.3" - "@babel/plugin-transform-modules-commonjs@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" @@ -1780,17 +969,6 @@ "@babel/helper-simple-access" "^7.16.0" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.12.1": - version "7.13.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz#6d066ee2bff3c7b3d60bf28dec169ad993831ae3" - integrity sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A== - dependencies: - "@babel/helper-hoist-variables" "^7.13.0" - "@babel/helper-module-transforms" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-validator-identifier" "^7.12.11" - babel-plugin-dynamic-import-node "^2.3.3" - "@babel/plugin-transform-modules-systemjs@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" @@ -1802,14 +980,6 @@ "@babel/helper-validator-identifier" "^7.15.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.12.1": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.0.tgz#2f8179d1bbc9263665ce4a65f305526b2ea8ac34" - integrity sha512-nPZdnWtXXeY7I87UZr9VlsWme3Y0cfFFE41Wbxz4bbaexAjNMInXPFUpRRUJ8NoMm0Cw+zxbqjdPmLhcjfazMw== - dependencies: - "@babel/helper-module-transforms" "^7.14.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-modules-umd@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" @@ -1818,13 +988,6 @@ "@babel/helper-module-transforms" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-named-capturing-groups-regex@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz#2213725a5f5bbbe364b50c3ba5998c9599c5c9d9" - integrity sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/plugin-transform-named-capturing-groups-regex@^7.14.7": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" @@ -1832,13 +995,6 @@ dependencies: "@babel/helper-create-regexp-features-plugin" "^7.16.0" -"@babel/plugin-transform-new-target@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz#e22d8c3af24b150dd528cbd6e685e799bf1c351c" - integrity sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-new-target@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" @@ -1846,14 +1002,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-object-super@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7" - integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/helper-replace-supers" "^7.12.13" - "@babel/plugin-transform-object-super@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" @@ -1862,13 +1010,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-replace-supers" "^7.16.0" -"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.2.tgz#e4290f72e0e9e831000d066427c4667098decc31" - integrity sha512-NxoVmA3APNCC1JdMXkdYXuQS+EMdqy0vIwyDHeKHiJKRxmp1qGSdb0JLEIoPRhkx6H/8Qi3RJ3uqOCYw8giy9A== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-parameters@^7.14.5", "@babel/plugin-transform-parameters@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz#fa9e4c874ee5223f891ee6fa8d737f4766d31d15" @@ -1876,13 +1017,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-property-literals@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81" - integrity sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-property-literals@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" @@ -1890,13 +1024,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-regenerator@^7.12.1": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39" - integrity sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ== - dependencies: - regenerator-transform "^0.14.2" - "@babel/plugin-transform-regenerator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" @@ -1904,13 +1031,6 @@ dependencies: regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz#7d9988d4f06e0fe697ea1d9803188aa18b472695" - integrity sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-reserved-words@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" @@ -1918,15 +1038,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-runtime@7.12.10": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.10.tgz#af0fded4e846c4b37078e8e5d06deac6cd848562" - integrity sha512-xOrUfzPxw7+WDm9igMgQCbO3cJKymX7dFdsgRr1eu9n3KjjyU4pptIXbXPseQDquw+W+RuJEJMHKHNsPNNm3CA== - dependencies: - "@babel/helper-module-imports" "^7.12.5" - "@babel/helper-plugin-utils" "^7.10.4" - semver "^5.5.1" - "@babel/plugin-transform-runtime@7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523" @@ -1939,13 +1050,6 @@ babel-plugin-polyfill-regenerator "^0.2.2" semver "^6.3.0" -"@babel/plugin-transform-shorthand-properties@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad" - integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-shorthand-properties@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" @@ -1953,14 +1057,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-spread@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd" - integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" - "@babel/plugin-transform-spread@^7.14.6": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" @@ -1969,13 +1065,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" -"@babel/plugin-transform-sticky-regex@^7.12.7": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f" - integrity sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-sticky-regex@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" @@ -1983,13 +1072,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-template-literals@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d" - integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-template-literals@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" @@ -1997,13 +1079,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-typeof-symbol@^7.12.10": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f" - integrity sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-typeof-symbol@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" @@ -2011,13 +1086,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-unicode-escapes@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74" - integrity sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-unicode-escapes@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" @@ -2025,14 +1093,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-unicode-regex@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac" - integrity sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-unicode-regex@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" @@ -2041,78 +1101,6 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/preset-env@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9" - integrity sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw== - dependencies: - "@babel/compat-data" "^7.12.7" - "@babel/helper-compilation-targets" "^7.12.5" - "@babel/helper-module-imports" "^7.12.5" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-validator-option" "^7.12.11" - "@babel/plugin-proposal-async-generator-functions" "^7.12.1" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-dynamic-import" "^7.12.1" - "@babel/plugin-proposal-export-namespace-from" "^7.12.1" - "@babel/plugin-proposal-json-strings" "^7.12.1" - "@babel/plugin-proposal-logical-assignment-operators" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-numeric-separator" "^7.12.7" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-catch-binding" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.7" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-proposal-unicode-property-regex" "^7.12.1" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.12.1" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-async-to-generator" "^7.12.1" - "@babel/plugin-transform-block-scoped-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.11" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-computed-properties" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-dotall-regex" "^7.12.1" - "@babel/plugin-transform-duplicate-keys" "^7.12.1" - "@babel/plugin-transform-exponentiation-operator" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-function-name" "^7.12.1" - "@babel/plugin-transform-literals" "^7.12.1" - "@babel/plugin-transform-member-expression-literals" "^7.12.1" - "@babel/plugin-transform-modules-amd" "^7.12.1" - "@babel/plugin-transform-modules-commonjs" "^7.12.1" - "@babel/plugin-transform-modules-systemjs" "^7.12.1" - "@babel/plugin-transform-modules-umd" "^7.12.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.1" - "@babel/plugin-transform-new-target" "^7.12.1" - "@babel/plugin-transform-object-super" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-property-literals" "^7.12.1" - "@babel/plugin-transform-regenerator" "^7.12.1" - "@babel/plugin-transform-reserved-words" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/plugin-transform-sticky-regex" "^7.12.7" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/plugin-transform-typeof-symbol" "^7.12.10" - "@babel/plugin-transform-unicode-escapes" "^7.12.1" - "@babel/plugin-transform-unicode-regex" "^7.12.1" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.12.11" - core-js-compat "^3.8.0" - semver "^5.5.0" - "@babel/preset-env@7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.8.tgz#254942f5ca80ccabcfbb2a9f524c74bca574005b" @@ -2192,17 +1180,6 @@ core-js-compat "^3.15.0" semver "^6.3.0" -"@babel/preset-modules@^0.1.3": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" - integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - "@babel/preset-modules@^0.1.4": version "0.1.5" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" @@ -2214,13 +1191,6 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/runtime@7.12.5", "@babel/runtime@^7.12.5": - version "7.12.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" - integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== - dependencies: - regenerator-runtime "^0.13.4" - "@babel/runtime@7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446" @@ -2228,22 +1198,13 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": - version "7.11.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" - integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== +"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" + integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@7.12.7": - version "7.12.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" - integrity sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.12.7" - "@babel/types" "^7.12.7" - "@babel/template@7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" @@ -2253,24 +1214,6 @@ "@babel/parser" "^7.14.5" "@babel/types" "^7.14.5" -"@babel/template@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" - integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/template@^7.12.13", "@babel/template@^7.12.7": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" - integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/parser" "^7.12.13" - "@babel/types" "^7.12.13" - "@babel/template@^7.14.5", "@babel/template@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" @@ -2280,36 +1223,7 @@ "@babel/parser" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" - integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.5" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.5" - "@babel/types" "^7.11.5" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.19" - -"@babel/traverse@^7.12.10", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.15", "@babel/traverse@^7.14.0", "@babel/traverse@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.2.tgz#9201a8d912723a831c2679c7ebbf2fe1416d765b" - integrity sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.14.2" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.14.2" - "@babel/types" "^7.14.2" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.14.8", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": +"@babel/traverse@^7.13.0", "@babel/traverse@^7.14.8", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== @@ -2324,24 +1238,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.4.4": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" - integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - -"@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.13", "@babel/types@^7.12.7", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.16", "@babel/types@^7.14.0", "@babel/types@^7.14.2", "@babel/types@^7.8.6": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.2.tgz#4208ae003107ef8a057ea8333e56eb64d2f6a2c3" - integrity sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw== - dependencies: - "@babel/helper-validator-identifier" "^7.14.0" - to-fast-properties "^2.0.0" - -"@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.16.0": +"@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.16.0", "@babel/types@^7.4.4", "@babel/types@^7.8.6": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== @@ -2349,6 +1246,18 @@ "@babel/helper-validator-identifier" "^7.15.7" to-fast-properties "^2.0.0" +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + "@csstools/convert-colors@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" @@ -2359,22 +1268,17 @@ resolved "https://registry.yarnpkg.com/@date-io/core/-/core-1.3.13.tgz#90c71da493f20204b7a972929cc5c482d078b3fa" integrity sha512-AlEKV7TxjeK+jxWVKcCFrfYAk8spX9aCyiToFIiLPtfQbsjmRGLIhb5VZgptQcJdHtLXo7+m0DuurwFgUToQuA== -"@date-io/core@^2.10.11": - version "2.10.11" - resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.10.11.tgz#b1a3d57730f3eaaab54d5658be4a71727297e357" - integrity sha512-keXQnwH0LM8wyvu+j5Z2KGK56D+eItjy7DnwuWl/oV+DM2UEYl0z5WhdPMpfswSyt/kjuPOzcVF/7u/skMLaoA== +"@date-io/core@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.11.0.tgz#28580cda1c8228ab2c7ed6aee673ef0495f913e6" + integrity sha512-DvPBnNoeuLaoSJZaxgpu54qzRhRKjSYVyQjhznTFrllKuDpm0sDFjHo6lvNLCM/cfMx2gb2PM2zY2kc9C8nmuw== -"@date-io/date-fns@^2.10.11": - version "2.10.11" - resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.10.11.tgz#1f3b40c6f2ea2e659260ca329fef80cb6dc64704" - integrity sha512-QG9IAZ4bvwkJftoSVKtdb5ISH+Qp4zilrjhzcL4RXaeqkfIWiFeXqQPgJljvPl6gQ04zf2SjGkWjdh1eJxxwmQ== +"@date-io/date-fns@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.11.0.tgz#142fbf954eda7ad66514af7a2802d78c4ea40053" + integrity sha512-mPQ71plBeFrArvBSHtjWMHXA89IUbZ6kuo2dsjlRC/1uNOybo91spIb+wTu03NxKTl8ut07s0jJ9svF71afpRg== dependencies: - "@date-io/core" "^2.10.11" - -"@discoveryjs/json-ext@0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752" - integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg== + "@date-io/core" "^2.11.0" "@discoveryjs/json-ext@0.5.3": version "0.5.3" @@ -2417,9 +1321,14 @@ polygon-clipping "0.15.3" "@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jcubic/lily@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@jcubic/lily/-/lily-0.3.0.tgz#00b229aab69fe094a57fd37f27d32dd4f380c1d1" + integrity sha512-4z6p4jLGSthc8gQ7wu4nHfGYn/IgCKFr+7hjuf80VdXUs7sm029mZGGDpS8sb29PVZWUBvMMTBCVGFhH2nN4Vw== "@jridgewell/resolve-uri@1.0.0": version "1.0.0" @@ -2449,14 +1358,14 @@ dependencies: tslib "^2.3.0" -"@material-ui/core@^4.11.4": - version "4.11.4" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.11.4.tgz#4fb9fe5dec5dcf780b687e3a40cff78b2b9640a4" - integrity sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg== +"@material-ui/core@^4.12.3": + version "4.12.3" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.3.tgz#80d665caf0f1f034e52355c5450c0e38b099d3ca" + integrity sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw== dependencies: "@babel/runtime" "^7.4.4" "@material-ui/styles" "^4.11.4" - "@material-ui/system" "^4.11.3" + "@material-ui/system" "^4.12.1" "@material-ui/types" "5.1.0" "@material-ui/utils" "^4.11.2" "@types/react-transition-group" "^4.2.0" @@ -2508,10 +1417,10 @@ jss-plugin-vendor-prefixer "^10.5.1" prop-types "^15.7.2" -"@material-ui/system@^4.11.3": - version "4.11.3" - resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.11.3.tgz#466bc14c9986798fd325665927c963eb47cc4143" - integrity sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw== +"@material-ui/system@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.1.tgz#2dd96c243f8c0a331b2bb6d46efd7771a399707c" + integrity sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw== dependencies: "@babel/runtime" "^7.4.4" "@material-ui/utils" "^4.11.2" @@ -2553,15 +1462,6 @@ dependencies: tslib "^2.0.0" -"@ngtools/webpack@11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-11.2.13.tgz#dbd77deb37ab57fd98678bd637fe87693fd71f4f" - integrity sha512-Wbv1zjLaS1zXcJ1wryYc6vhKWq8r/+ZrdN5SlRIf3xf7fwuTymbvL41SndUibssXir6s4vePYqZL241nkThx9g== - dependencies: - "@angular-devkit/core" "11.2.13" - enhanced-resolve "5.7.0" - webpack-sources "2.2.0" - "@ngtools/webpack@12.2.13", "@ngtools/webpack@~12.2.13": version "12.2.13" resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.2.13.tgz#44d711edfa39d175a2d655aa5c6f9968dfedcc35" @@ -2581,25 +1481,25 @@ dependencies: tslib "^2.0.0" -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" - integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: - "@nodelib/fs.stat" "2.0.3" + "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" - integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" - integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: - "@nodelib/fs.scandir" "2.1.3" + "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" "@npmcli/fs@^1.0.0": @@ -2633,16 +1533,17 @@ npm-normalize-package-bin "^1.0.1" "@npmcli/move-file@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.0.1.tgz#de103070dac0f48ce49cf6693c23af59c0f70464" - integrity sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw== + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== dependencies: mkdirp "^1.0.4" + rimraf "^3.0.2" "@npmcli/node-gyp@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" - integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== + version "1.0.3" + resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" + integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== "@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": version "1.3.2" @@ -2675,16 +1576,31 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== -"@trysound/sax@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669" - integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow== - "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + "@turf/bbox@*", "@turf/bbox@^6.3.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5" @@ -2846,25 +1762,25 @@ "@turf/helpers" "^6.5.0" "@turf/meta" "^6.5.0" -"@types/canvas-gauges@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz#fb9ece324cb15ae137791ad21eb2db70e11a7210" - integrity sha512-oWCq0XjsTBXPtMKXoW23ORbMWguC2Fa8o5NiZVYiUoQMMrpNLKj1E+LDznlMpcib3iyWVIy+TEpc/ea6LMbW3Q== +"@types/canvas-gauges@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.4.tgz#063881264597d098e78cf5ad921e8ed20ae2ad16" + integrity sha512-JTvqQWrqcrgzCp/9+uzwUvPef2qAEnBJvm+bL9kvulzhXapDeNaGQXCIAZp+hOryusjOyndvP1za2HZooUV0XA== "@types/component-emitter@^1.2.10": - version "1.2.10" - resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.10.tgz#ef5b1589b9f16544642e473db5ea5639107ef3ea" - integrity sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg== + version "1.2.11" + resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506" + integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== -"@types/cookie@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.0.tgz#14f854c0f93d326e39da6e3b6f34f7d37513d108" - integrity sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg== +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== -"@types/cors@^2.8.8": - version "2.8.10" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.10.tgz#61cc8469849e5bcdd0c7044122265c39cec10cf4" - integrity sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ== +"@types/cors@^2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== "@types/eslint-scope@^3.7.0": version "3.7.1" @@ -2887,10 +1803,10 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== -"@types/flot@^0.0.31": - version "0.0.31" - resolved "https://registry.yarnpkg.com/@types/flot/-/flot-0.0.31.tgz#0daca37c6c855b69a0a7e2e37dd0f84b3db8c8c1" - integrity sha512-X+RcMQCqPlQo8zPT6cUFTd/PoYBShMQlHUeOXf05jWlfYnvLuRmluB9z+2EsOKFgUzqzZve5brx+gnFxBaHEUw== +"@types/flot@^0.0.32": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/flot/-/flot-0.0.32.tgz#2ab260f2958dcab1acfb5c24b87898f1d22417d8" + integrity sha512-aturel4TWMY86N4Pkpc9pSoUd/p8c3BjGj4fTDkaZIpkRPzLH1VXZCAKGUywcFkTqgZMhPJFPWxd4pl87y8h/w== dependencies: "@types/jquery" "*" @@ -2899,84 +1815,62 @@ resolved "https://registry.yarnpkg.com/@types/flowjs/-/flowjs-2.13.3.tgz#4f1ba77d9259f4be83ecaa985db96fa758b2fd22" integrity sha512-VeWuL+Whk6lUSWX/g0LzLNyZywyTB5wZ2L6mPvD8/u5pgLF2HwyV7nZ1UArOifalJ5UE1CcJbPLKS+jc5+Z2ig== -"@types/geojson@*": - version "7946.0.7" - resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad" - integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ== - -"@types/geojson@7946.0.8": +"@types/geojson@*", "@types/geojson@7946.0.8": version "7946.0.8" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca" integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA== "@types/glob@^7.1.1": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" - integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== dependencies: "@types/minimatch" "*" "@types/node" "*" -"@types/jasmine@*": - version "3.5.14" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.5.14.tgz#f41a14e8ffa939062a71cf9722e5ee7d4e1f94af" - integrity sha512-Fkgk536sHPqcOtd+Ow+WiUNuk0TSo/BntKkF8wSvcd6M2FvPjeXcUE6Oz/bwDZiUZEaXLslAgw00Q94Pnx6T4w== +"@types/hammerjs@^2.0.39": + version "2.0.40" + resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.40.tgz#ded0240b6ea1ad7afc1e60374c49087aaea5dbd8" + integrity sha512-VbjwR1fhsn2h2KXAY4oy1fm7dCxaKy0D+deTb8Ilc3Eo3rc5+5eA4rfYmZaHgNJKxVyI0f6WIXzO2zLkVmQPHA== -"@types/jasmine@~3.7.4": - version "3.7.4" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.7.4.tgz#99a49aa9a5f8dc86fc249ed13ed59552c6ce862d" - integrity sha512-L3FKeEwMm8e8hqGvt7cSesVmGtavpRyHV1FNDq+Pm5pS4x5eFmE70ZERXCSBWAiLQqXBcZRUrwV59FZLQl/GxQ== +"@types/jasmine@*", "@types/jasmine@~3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.10.2.tgz#1b9f9ba9ad7bfd7d322f7ed9d8753220b1c84b52" + integrity sha512-qs4xjVm4V/XjM6owGm/x6TNmhGl5iKX8dkTdsgdgl9oFnqgzxLepnS7rN9Tdo7kDmnFD/VEqKrW57cGD2odbEg== -"@types/jasminewd2@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.9.tgz#db3946314605deea9d5c7aea0b61d807089ba76d" - integrity sha512-Oz+Faunpe2SimFvkMYMXxpK89WXl7rZHG8abTOKcGndu4xOoSbUZ+jUdZ0LQpmDqPEGLBWXF/yZP1tlsplGhzw== +"@types/jasminewd2@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.10.tgz#ae31c237aa6421bde30f1058b1d20f4577e54443" + integrity sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g== dependencies: "@types/jasmine" "*" -"@types/jquery@*", "@types/jquery@^3.5.2": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.2.tgz#e17c1756ecf7bbb431766c6761674a5d1de16579" - integrity sha512-+MFOdKF5Zr41t3y2wfzJvK1PrUK0KtPLAFwYownp/0nCoMIANDDu5aFSpWfb8S0ZajCSNeaBnMrBGxksXK5yeg== - dependencies: - "@types/sizzle" "*" - -"@types/jquery@^3.5.5": - version "3.5.5" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.5.tgz#2c63f47c9c8d96693d272f5453602afd8338c903" - integrity sha512-6RXU9Xzpc6vxNrS6FPPapN1SxSHgQ336WC6Jj/N8q30OiaBZ00l1GBgeP7usjVZPivSkGUfL1z/WW6TX989M+w== +"@types/jquery@*", "@types/jquery@^3.5.6", "@types/jquery@^3.5.9": + version "3.5.9" + resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.9.tgz#08e4b1dcff0626926ffe545a2bc90f18140c53d6" + integrity sha512-B8pDk+sH/tSv/HKdx6EQER6BfUOb2GtKs0LOmozziS4h7cbe8u/eYySfUAeTwD+J09SqV3man7AMWIA5mgzCBA== dependencies: "@types/sizzle" "*" -"@types/js-beautify@^1.13.1": - version "1.13.1" - resolved "https://registry.yarnpkg.com/@types/js-beautify/-/js-beautify-1.13.1.tgz#d4739266c5dcad561226cd1ec5407fa0542d863d" - integrity sha512-F3YCoZS//n74Wu+hxoVrxX1H8qaWo+WAgQ+ObmFH4ZFwI0fIwiJTW7pvkCRShw8ST7+ej7sB68K+ZHAZgK4S4Q== +"@types/js-beautify@^1.13.3": + version "1.13.3" + resolved "https://registry.yarnpkg.com/@types/js-beautify/-/js-beautify-1.13.3.tgz#53839bb5b766d0fb45e87386100bb3bcbb7dca9d" + integrity sha512-ucIPw5gmNyvRKi6mpeojlqp+T+6ZBJeU+kqMDnIEDlijEU4QhLTon90sZ3cz9HZr+QTwXILjNsMZImzA7+zuJA== -"@types/json-schema@*", "@types/json-schema@^7.0.8": +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/json-schema@^7.0.5": - version "7.0.6" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" - integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== - -"@types/json-schema@^7.0.6": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" - integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== - "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/jstree@^3.3.40": - version "3.3.40" - resolved "https://registry.yarnpkg.com/@types/jstree/-/jstree-3.3.40.tgz#835737a262ea2572df9ffafc68c08633f4554aa4" - integrity sha512-+6mdAX+vaj962NSd1nnzSLBWD2obUQf5+1yxR+4/g+abpEIQFsI+CcqP4l+cS6H9P07sTONMbR3Z09bPpDzkNg== +"@types/jstree@^3.3.41": + version "3.3.41" + resolved "https://registry.yarnpkg.com/@types/jstree/-/jstree-3.3.41.tgz#820ce1f82bbb2441eaf9fb76451750e2810f5856" + integrity sha512-M4ia6tSKOAU/8v2Ir1Kyo3/XE4EWxw5ulnzbE/nmvw7YugxWhRfTIc6i2ubvJ3GQpdXzJ11bH+GT3VhJNcJadQ== dependencies: "@types/jquery" "*" @@ -3008,24 +1902,17 @@ dependencies: "@types/leaflet" "*" -"@types/leaflet@*": - version "1.5.17" - resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b" - integrity sha512-2XYq9k6kNjhNI7PaTz8Rdxcc8Vzwu97OaS9CtcrTxnTSxFUGwjlGjTDvhTLJU+JRSfZ4lBwGcl0SjZHALdVr6g== - dependencies: - "@types/geojson" "*" - -"@types/leaflet@^1.7.6": +"@types/leaflet@*", "@types/leaflet@^1.7.6": version "1.7.6" resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.6.tgz#6580f4babb648972c5af3abc3d66866753fa9311" integrity sha512-Emkz3V08QnlelSbpT46OEAx+TBZYTOX2r1yM7W+hWg5+djHtQ1GbEXBDRLaqQDOYcDI51Ss0ayoqoKD4CtLUDA== dependencies: "@types/geojson" "*" -"@types/lodash@^4.14.170": - version "4.14.170" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6" - integrity sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q== +"@types/lodash@^4.14.177": + version "4.14.177" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578" + integrity sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw== "@types/marked@^2.0.0": version "2.0.5" @@ -3033,9 +1920,9 @@ integrity sha512-shRZ7XnYFD/8n8zSjKvFdto1QNSf4tONZIlNEZGrJe8GsOE8DL/hG1Hbl8gZlfLnjS7+f5tZGIaTgfpyW38h4w== "@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== "@types/moment-timezone@^0.5.30": version "0.5.30" @@ -3044,25 +1931,20 @@ dependencies: moment-timezone "*" -"@types/mousetrap@1.6.3": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.3.tgz#3159a01a2b21c9155a3d8f85588885d725dc987d" - integrity sha512-13gmo3M2qVvjQrWNseqM3+cR6S2Ss3grbR2NZltgMq94wOwqJYQdgn8qzwDshzgXqMlSUtyPZjysImmktu22ew== - "@types/mousetrap@^1.6.0": - version "1.6.4" - resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.4.tgz#32503197fca4168b10bf251c1d677a9b5b1c2415" - integrity sha512-+Y900DGhe+f+4lRwHm9krsKfsiXcbdOhzTsLbytU4MiG8wE9xOw7CFKtgYKfqEAcUdWEGZRyuTxoyFl2Gx6Rdg== + version "1.6.8" + resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.8.tgz#448929e6dc21126392830465fdb9d4a2cfc16a88" + integrity sha512-zTqjvgCUT5EoXqbqmd8iJMb4NJqyV/V7pK7AIKq7qcaAsJIpGlTVJS1HQM6YkdHCdnkNSbhcQI7MXYxFfE3iCA== -"@types/node@*": - version "14.11.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.5.tgz#fecad41c041cae7f2404ad4b2d0742fdb628b305" - integrity sha512-jVFzDV6NTbrLMxm4xDSIW/gKnk8rQLF9wAzLWIOg+5nU6ACrIMndeBdXci0FGtqJbP9tQvm6V39eshc96TO2wQ== +"@types/node@*", "@types/node@>=10.0.0": + version "16.11.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234" + integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw== -"@types/node@>=10.0.0": - version "15.6.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.6.1.tgz#32d43390d5c62c5b6ec486a9bc9c59544de39a08" - integrity sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA== +"@types/node@~15.14.9": + version "15.14.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" + integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== "@types/parse-json@^4.0.0": version "4.0.0" @@ -3070,51 +1952,57 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prop-types@*": - version "15.7.3" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" - integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== "@types/q@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= -"@types/raphael@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@types/raphael/-/raphael-2.3.1.tgz#5e8e69c35f2c8a89a6e5cf0f9ff87004bbc6f3bb" - integrity sha512-zsocvfGMgQT9kVwGYthhWifd5iUw3nhzXZyO7+V9+B69kNYi6x0FN9W2k9dLJecXsk4HR6aKVmaSQjkWGo3N9w== +"@types/raphael@^2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/raphael/-/raphael-2.3.2.tgz#833eff033c33fb1a3935882bc29c82908cb9a734" + integrity sha512-RbEkYHuQbb2LYN0MN+Gk3CN3y0122uTLI41z8l62BFhnxS/ylVkZT2D1PLdmLTu5itV1iHh9SF+kDomY3DrZig== -"@types/react-dom@^16.9.8": - version "16.9.8" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" - integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== +"@types/react-dom@^17.0.11": + version "17.0.11" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466" + integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q== dependencies: "@types/react" "*" "@types/react-transition-group@^4.2.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.0.tgz#882839db465df1320e4753e6e9f70ca7e9b4d46d" - integrity sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w== + version "4.4.4" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" + integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug== dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.9.51": - version "16.9.51" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.51.tgz#f8aa51ffa9996f1387f63686696d9b59713d2b60" - integrity sha512-lQa12IyO+DMlnSZ3+AGHRUiUcpK47aakMMoBG8f7HGxJT8Yfe+WE128HIXaHOHVPReAW0oDS3KAI0JI2DDe1PQ== +"@types/react@*", "@types/react@^17.0.37": + version "17.0.37" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.37.tgz#6884d0aa402605935c397ae689deed115caad959" + integrity sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg== dependencies: "@types/prop-types" "*" + "@types/scheduler" "*" csstype "^3.0.2" +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + "@types/selenium-webdriver@^3.0.0": - version "3.0.17" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz#50bea0c3c2acc31c959c5b1e747798b3b3d06d4b" - integrity sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw== + version "3.0.19" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.19.tgz#28ecede76f15b13553b4e86074d4cf9a0bbe49c4" + integrity sha512-OFUilxQg+rWL2FMxtmIgCkUDlJB6pskkpvmew7yeXfzzsOBb5rc+y2+DjHm+r3r1ZPPcJefK3DveNSYWGiy68g== "@types/sizzle@*": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" - integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== + version "2.3.3" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef" + integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ== "@types/source-list-map@*": version "0.1.2" @@ -3122,28 +2010,33 @@ integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== "@types/styled-jsx@^2.2.8": - version "2.2.8" - resolved "https://registry.yarnpkg.com/@types/styled-jsx/-/styled-jsx-2.2.8.tgz#b50d13d8a3c34036282d65194554cf186bab7234" - integrity sha512-Yjye9VwMdYeXfS71ihueWRSxrruuXTwKCbzue4+5b2rjnQ//AtyM7myZ1BEhNhBQ/nL/RE7bdToUoLln2miKvg== + version "2.2.9" + resolved "https://registry.yarnpkg.com/@types/styled-jsx/-/styled-jsx-2.2.9.tgz#e50b3f868c055bcbf9bc353eca6c10fdad32a53f" + integrity sha512-W/iTlIkGEyTBGTEvZCey8EgQlQ5l0DwMqi3iOXlLs2kyBwYTXHKEiU6IZ5EwoRwngL8/dGYuzezSup89ttVHLw== dependencies: "@types/react" "*" -"@types/tinycolor2@^1.4.2": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.2.tgz#721ca5c5d1a2988b4a886e35c2ffc5735b6afbdf" - integrity sha512-PeHg/AtdW6aaIO2a+98Xj7rWY4KC1E6yOy7AFknJQ7VXUGNrMlyxDFxJo7HqLtjQms/ZhhQX52mLVW/EX3JGOw== +"@types/systemjs@6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@types/systemjs/-/systemjs-6.1.1.tgz#eae17f2a080e867d01a2dd614f524ab227cf5a41" + integrity sha512-d1M6eDKBGWx7RbYy295VEFoOF9YDJkPI959QYnmzcmeaV+SP4D0xV7dEh3sN5XF3GvO3PhGzm+17Z598nvHQuQ== -"@types/tooltipster@^0.0.30": - version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/tooltipster/-/tooltipster-0.0.30.tgz#10deda04d1ce52e0fefc18079ae91548663e2400" - integrity sha512-JqgcjpkDOMjsiVg3tqMIDgxnealN9/+DY6+z9OMeSd4fRovHINr/tHKtBJXDHI2DKh+ygyqMHsPTct+flNS+bw== +"@types/tinycolor2@^1.4.3": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.3.tgz#ed4a0901f954b126e6a914b4839c77462d56e706" + integrity sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ== + +"@types/tooltipster@^0.0.31": + version "0.0.31" + resolved "https://registry.yarnpkg.com/@types/tooltipster/-/tooltipster-0.0.31.tgz#db6c78b5ad709fe5dc9c78cf15a6a2068b4f72b0" + integrity sha512-tDAxe2Q67VoQyeEW6oweNDfw4nNmodFGkHdPQdeBCCusf2d3qFbDLFkYnntgSwcD00Fkhh8mSguaP6w5muvZpg== dependencies: "@types/jquery" "*" "@types/webpack-sources@^0.1.5": - version "0.1.8" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.8.tgz#078d75410435993ec8a0a2855e88706f3f751f81" - integrity sha512-JHB2/xZlXOjzjBB6fMOpH1eQAfsrpqVVIbneE0Rok16WXwFaznaI5vfg75U5WgGJm7V9W1c4xeRQDjX/zwvghA== + version "0.1.9" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.9.tgz#da69b06eb34f6432e6658acb5a6893c55d983920" + integrity sha512-bvzMnzqoK16PQIC8AYHNdW45eREJQMd6WG/msQWX5V2+vZmODCOPb4TJcbgRljTZZTwTM4wUMcsI8FftNA7new== dependencies: "@types/node" "*" "@types/source-list-map" "*" @@ -3157,64 +2050,21 @@ "@webassemblyjs/helper-numbers" "1.11.1" "@webassemblyjs/helper-wasm-bytecode" "1.11.1" -"@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" - integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== - dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@webassemblyjs/floating-point-hex-parser@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== -"@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" - integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== - "@webassemblyjs/helper-api-error@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== -"@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" - integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== - "@webassemblyjs/helper-buffer@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== -"@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" - integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== - -"@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" - integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" - integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== - -"@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" - integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-numbers@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" @@ -3229,11 +2079,6 @@ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== -"@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" - integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== - "@webassemblyjs/helper-wasm-section@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" @@ -3244,16 +2089,6 @@ "@webassemblyjs/helper-wasm-bytecode" "1.11.1" "@webassemblyjs/wasm-gen" "1.11.1" -"@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" - integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/ieee754@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" @@ -3261,13 +2096,6 @@ dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" - integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - "@webassemblyjs/leb128@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" @@ -3275,23 +2103,11 @@ dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" - integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== - dependencies: - "@xtuc/long" "4.2.2" - "@webassemblyjs/utf8@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== -"@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" - integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== - "@webassemblyjs/wasm-edit@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" @@ -3306,20 +2122,6 @@ "@webassemblyjs/wasm-parser" "1.11.1" "@webassemblyjs/wast-printer" "1.11.1" -"@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" - integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" - "@webassemblyjs/wasm-gen@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" @@ -3331,17 +2133,6 @@ "@webassemblyjs/leb128" "1.11.1" "@webassemblyjs/utf8" "1.11.1" -"@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" - integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - "@webassemblyjs/wasm-opt@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" @@ -3352,16 +2143,6 @@ "@webassemblyjs/wasm-gen" "1.11.1" "@webassemblyjs/wasm-parser" "1.11.1" -"@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" - integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wasm-parser@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" @@ -3374,30 +2155,6 @@ "@webassemblyjs/leb128" "1.11.1" "@webassemblyjs/utf8" "1.11.1" -"@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" - integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" - integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" - "@xtuc/long" "4.2.2" - "@webassemblyjs/wast-printer@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" @@ -3406,15 +2163,6 @@ "@webassemblyjs/ast" "1.11.1" "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" - integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@xtuc/long" "4.2.2" - "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -3448,33 +2196,26 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -ace-builds@^1.4.12, ace-builds@^1.4.6: - version "1.4.12" - resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.12.tgz#888efa386e36f4345f40b5233fcc4fe4c588fae7" - integrity sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg== +ace-builds@^1.4.13: + version "1.4.13" + resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.13.tgz#186f42d3849ebcc6a48b93088a058489897514c1" + integrity sha512-SOLzdaQkY6ecPKYRDDg+MY1WoGgXA34cIvYJNNoBMGGUswHmlauU2Hy0UL96vW0Fs/LgFbMUjD+6vqzWTldIYQ== acorn-import-assertions@^1.7.6: version "1.8.0" resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== -acorn@^6.4.1: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== acorn@^8.4.1: version "8.6.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== -add-dom-event-listener@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310" - integrity sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw== - dependencies: - object-assign "4.x" - adjust-sourcemap-loader@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz#fc4a0fd080f7d10471f30a7320f25560ade28c99" @@ -3531,20 +2272,24 @@ ajv-formats@2.1.0: dependencies: ajv "^8.0.0" -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@6.12.6, ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" + fast-deep-equal "^3.1.3" ajv@8.6.2: version "8.6.2" @@ -3556,17 +2301,17 @@ ajv@8.6.2: require-from-string "^2.0.2" uri-js "^4.2.2" -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: - version "6.12.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" - integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== +ajv@^6.1.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0: +ajv@^8.0.0, ajv@^8.8.0: version "8.8.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== @@ -3581,12 +2326,12 @@ alphanum-sort@^1.0.2: resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= -angular-gridster2@~11.2.0: - version "11.2.0" - resolved "https://registry.yarnpkg.com/angular-gridster2/-/angular-gridster2-11.2.0.tgz#57239e639d16b7b1bcd6255aa8fee55151dd65d7" - integrity sha512-9+4Qt2/mPKAzGhhzp2Ag++WQbvr3Ry3dbfHG1XI596jpKh1ZtYvTLrh0Fn6jJEq248F1VN0xob9K9PzTH4P/2A== +angular-gridster2@~12.1.1: + version "12.1.1" + resolved "https://registry.yarnpkg.com/angular-gridster2/-/angular-gridster2-12.1.1.tgz#699cd0a2477b81b052f6bd7b336ba7cc2adc8bc3" + integrity sha512-HK7vf212LSn7mp8g4sNA6/X8TQN4wJyHupKemx+PUPmTs6FHDyquUMUFXYxANR47jdyLEMW/DxCDI0bEhIIChw== dependencies: - tslib "^2.0.0" + tslib "^2.1.0" angular2-hotkeys@^2.4.0: version "2.4.0" @@ -3608,11 +2353,11 @@ ansi-colors@^3.0.0: integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: - type-fest "^0.11.0" + type-fest "^0.21.3" ansi-html@0.0.7: version "0.0.7" @@ -3624,20 +2369,15 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^2.2.1: version "2.2.1" @@ -3658,6 +2398,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansidec@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/ansidec/-/ansidec-0.3.4.tgz#e12d267d6b1f122d2da5b98fe0de1f98d14ac62b" + integrity sha512-Ydgbey4zqUmmNN2i2OVeVHXig3PxHRbok2X6B2Sogmb92JzZUFfTL806dT7os6tBL1peXItfeFt76CP3zsoXUg== + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -3666,14 +2411,6 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - anymatch@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" @@ -3687,15 +2424,15 @@ app-root-path@^3.0.0: resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== -aproba@^1.0.3, aproba@^1.1.1: +aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + version "1.1.7" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -3772,20 +2509,10 @@ arrify@^1.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== dependencies: safer-buffer "~2.1.0" @@ -3794,14 +2521,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -3839,23 +2558,11 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -attr-accept@^2.0.0: +attr-accept@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -autoprefixer@10.2.4: - version "10.2.4" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.4.tgz#c0e7cf24fcc6a1ae5d6250c623f0cb8beef2f7e1" - integrity sha512-DCCdUQiMD+P/as8m3XkeTUkUKuuRqLGcwD0nll7wevhqoJfMRpJlkFd1+MQh1pvupjiQuip42lc/VFvfUTMSKw== - dependencies: - browserslist "^4.16.1" - caniuse-lite "^1.0.30001181" - colorette "^1.2.1" - fraction.js "^4.0.13" - normalize-range "^0.1.2" - postcss-value-parser "^4.1.0" - autoprefixer@^9.6.1: version "9.8.8" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" @@ -3875,9 +2582,9 @@ aws-sign2@~0.7.0: integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" - integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA== + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== axobject-query@2.0.2: version "2.0.2" @@ -3928,24 +2635,19 @@ babel-plugin-polyfill-regenerator@^0.2.2: "@babel/helper-define-polyfill-provider" "^0.2.4" balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base64-arraybuffer@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812" - integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-arraybuffer@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45" integrity sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ== -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== +base64-arraybuffer@^1.0.1, base64-arraybuffer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz#87bd13525626db4a9838e00a508c2b73efcf348c" + integrity sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA== base64-js@^1.2.0, base64-js@^1.3.1: version "1.5.1" @@ -3993,9 +2695,9 @@ binary-extensions@^1.0.0: integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== binary-extensions@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" - integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== bindings@^1.5.0: version "1.5.0" @@ -4004,7 +2706,7 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^4.0.3, bl@^4.1.0: +bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -4020,21 +2722,6 @@ blocking-proxy@^1.0.0: dependencies: minimist "^1.2.0" -bluebird@^3.5.5: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0: - version "4.11.9" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" - integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== - -bn.js@^5.1.1: - version "5.1.3" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" - integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== - body-parser@1.19.0, body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -4099,83 +2786,7 @@ braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@^4.0.0, browserslist@^4.9.1: - version "4.14.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.5.tgz#1c751461a102ddc60e40993639b709be7f2c4015" - integrity sha512-Z+vsCZIvCBvqLoYkBFTwEYH3v5MCQbsAjp50ERycpOjnPmolg1Gjy4+KaWWpm8QOJt9GHkhdqAl14NpCX73CWA== - dependencies: - caniuse-lite "^1.0.30001135" - electron-to-chromium "^1.3.571" - escalade "^3.1.0" - node-releases "^1.1.61" - -browserslist@^4.12.0, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.6.4: +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.6.4, browserslist@^4.9.1: version "4.18.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== @@ -4186,67 +2797,24 @@ browserslist@^4.12.0, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^ node-releases "^2.0.1" picocolors "^1.0.0" -browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.1, browserslist@^4.16.6: - version "4.16.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" - integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== - dependencies: - caniuse-lite "^1.0.30001219" - colorette "^1.2.2" - electron-to-chromium "^1.3.723" - escalade "^3.1.1" - node-releases "^1.1.71" - browserstack@^1.5.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.6.0.tgz#5a56ab90987605d9c138d7a8b88128370297f9bf" - integrity sha512-HJDJ0TSlmkwnt9RZ+v5gFpa1XZTBYTj0ywvLwJ3241J7vMw2jAsGNVhKHtmCOyg+VxeLZyaibO9UL71AsUeDIw== + version "1.6.1" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.6.1.tgz#e051f9733ec3b507659f395c7a4765a1b1e358b3" + integrity sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw== dependencies: https-proxy-agent "^2.2.1" -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - -buffer-from@^1.0.0, buffer-from@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -buffer@^5.4.3, buffer@^5.5.0: +buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -4259,11 +2827,6 @@ builtin-modules@^1.1.1: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" @@ -4279,29 +2842,6 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -cacache@15.0.5, cacache@^15.0.5: - version "15.0.5" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0" - integrity sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A== - dependencies: - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.0" - tar "^6.0.2" - unique-filename "^1.1.1" - cacache@15.2.0: version "15.2.0" resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.2.0.tgz#73af75f77c58e72d8c630a7a2858cb18ef523389" @@ -4325,28 +2865,7 @@ cacache@15.2.0: tar "^6.0.2" unique-filename "^1.1.1" -cacache@^12.0.2: - version "12.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^15.2.0: +cacache@^15.0.5, cacache@^15.2.0: version "15.3.0" resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== @@ -4385,6 +2904,14 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -4395,11 +2922,6 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== - caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -4410,20 +2932,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001135: - version "1.0.30001146" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001146.tgz#c61fcb1474520c1462913689201fb292ba6f447c" - integrity sha512-VAy5RHDfTJhpxnDdp2n40GPPLp3KqNrXz1QqFv4J64HvArKs8nuNMOWkB3ICOaBTU/Aj4rYAo/ytdQDDFF/Pug== - -caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001280: - version "1.0.30001283" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001283.tgz#8573685bdae4d733ef18f78d44ba0ca5fe9e896b" - integrity sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg== - -caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001219: - version "1.0.30001228" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" - integrity sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001280: + version "1.0.30001284" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001284.tgz#d3653929ded898cd0c1f09a56fd8ca6952df4fca" + integrity sha512-t28SKa7g6kiIQi6NHeOcKrOrGMzCRrXvlasPwWC26TH2QNdglgzQIRUuJ0cR3NeQPH+5jpuveeeSFDLm2zbkEw== canonical-path@1.0.0: version "1.0.0" @@ -4460,15 +2972,7 @@ chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.1.1: +chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -4481,22 +2985,7 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -"chokidar@>=2.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.4.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" - integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.4.0" - optionalDependencies: - fsevents "~2.1.2" - -"chokidar@>=3.0.0 <4.0.0": +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== @@ -4530,51 +3019,21 @@ chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.4.2: - version "3.5.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" - integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.5.0" - optionalDependencies: - fsevents "~2.3.1" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - chownr@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== chrome-trace-event@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" - integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== - dependencies: - tslib "^1.9.0" + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - circular-dependency-plugin@5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz#39e836079db1d3cf2f988dc48c5188a44058b600" @@ -4591,9 +3050,9 @@ class-utils@^0.3.5: static-extend "^0.1.1" classnames@2.x, classnames@^2.2.1, classnames@^2.2.6: - version "2.2.6" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" - integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== clean-stack@^2.0.0: version "2.2.0" @@ -4608,24 +3067,15 @@ cli-cursor@^3.1.0: restore-cursor "^3.1.0" cli-spinners@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.0.tgz#36c7dc98fb6a9a76bd6238ec3f77e2425627e939" - integrity sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q== + version "2.6.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== -clipboard@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376" - integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg== - dependencies: - good-listener "^1.2.2" - select "^1.1.2" - tiny-emitter "^2.0.0" - cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -4729,25 +3179,15 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colord@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.0.0.tgz#f8c19f2526b7dc5b22d6e57ef102f03a2a43a3d8" - integrity sha512-WMDFJfoY3wqPZNpKUFdse3HhD5BHCbE9JCdxRzoVH+ywRITGOeWAHNkGEmyxLlErEpN9OLMWgdM9dWQtDk5dog== - colord@^2.9.1: version "2.9.1" resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.1.tgz#c961ea0efeb57c9f0f4834458f26cb9cc4a3f90e" integrity sha512-4LBMSt09vR0uLnPVkOUBnmxgoaeN4ewRbx801wY/bXcltXfpR/G46OdWn96XpYmCWuYvO46aBZP4NgX8HpNAcw== -colorette@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" - integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== - colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== colors@1.4.0, colors@^1.4.0: version "1.4.0" @@ -4766,26 +3206,21 @@ commander@^2.11.0, commander@^2.12.1, commander@^2.19.0, commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - -commander@^7.1.0, commander@^7.2.0: +commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +commander@^8.0.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -compass-sass-mixins@^0.12.7: - version "0.12.7" - resolved "https://registry.yarnpkg.com/compass-sass-mixins/-/compass-sass-mixins-0.12.7.tgz#2ac4d310f2ebe518b7d6aca4ae24f1d325409e8c" - integrity sha1-KsTTEPLr5Ri31qykriTx0yVAnow= - component-emitter@^1.2.1, component-emitter@~1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -4798,16 +3233,13 @@ compressible@~2.0.16: dependencies: mime-db ">= 1.43.0 < 2" -compression-webpack-plugin@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-6.1.1.tgz#ae8e4b2ffdb7396bb776e66918d751a20d8ccf0e" - integrity sha512-BEHft9M6lwOqVIQFMS/YJGmeCYXVOakC5KzQk05TFpMBlODByh1qNsZCWjUBxCQhUP9x0WfGidxTbGkjbWO/TQ== +compression-webpack-plugin@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-9.0.1.tgz#fd80350670ca88cc8a1c0edac40ee92a0e06fcd4" + integrity sha512-vqlhZIPSyCpy6eaYWy8iPhteLWpARKotRiN5B/jr7lLowJv1GVc98Snn1Dcxe0+SKbfydLu7qZcnNuP+AyG19Q== dependencies: - cacache "^15.0.5" - find-cache-dir "^3.3.1" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" + schema-utils "^4.0.0" + serialize-javascript "^6.0.0" compression@^1.7.4: version "1.7.4" @@ -4827,20 +3259,10 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - config-chain@^1.1.12: - version "1.1.12" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" - integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== dependencies: ini "^1.3.4" proto-list "~1.2.1" @@ -4860,21 +3282,11 @@ connect@^3.7.0: parseurl "~1.3.3" utils-merge "1.0.1" -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -4888,9 +3300,9 @@ content-type@~1.0.4: integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== convert-source-map@^1.5.1, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== dependencies: safe-buffer "~5.1.1" @@ -4916,40 +3328,11 @@ copy-anything@^2.0.1: dependencies: is-what "^3.12.0" -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-webpack-plugin@6.3.2: - version "6.3.2" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.3.2.tgz#0e920a6c181a5052aa6e2861b164bda03f83afeb" - integrity sha512-MgJ1uouLIbDg4ST1GzqrGQyKoXY5iPqi6fghFqarijam7FQcBa/r6Rg0VkoIuzx75Xq8iAMghyOueMkWUQ5OaA== - dependencies: - cacache "^15.0.5" - fast-glob "^3.2.4" - find-cache-dir "^3.3.1" - glob-parent "^5.1.1" - globby "^11.0.1" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" - copy-webpack-plugin@9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz#b71d21991599f61a4ee00ba79087b8ba279bbb59" @@ -4971,34 +3354,26 @@ core-js-compat@^3.15.0, core-js-compat@^3.16.2: browserslist "^4.18.1" semver "7.0.0" -core-js-compat@^3.8.0: - version "3.12.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.12.1.tgz#2c302c4708505fa7072b0adb5156d26f7801a18b" - integrity sha512-i6h5qODpw6EsHAoIdQhKoZdWn+dGBF3dSS8m5tif36RlWvW3A6+yu2S16QHUo3CrkzrnEskMAt9f8FxmY9fhWQ== - dependencies: - browserslist "^4.16.6" - semver "7.0.0" - core-js@3.16.0: version "3.16.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.0.tgz#1d46fb33720bc1fa7f90d20431f36a5540858986" integrity sha512-5+5VxRFmSf97nM8Jr2wzOwLqRo6zphH2aX+7KsAUONObyzakDNq2G/bgbhinxB4PoV9L3aXQYhiDKyIKWd2c8g== -core-js@3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.3.tgz#c21906e1f14f3689f93abcc6e26883550dd92dd0" - integrity sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q== - -core-js@^3.18.3: - version "3.18.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.3.tgz#86a0bba2d8ec3df860fefcc07a8d119779f01509" - integrity sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw== +core-js@^3.19.2: + version "3.19.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.19.2.tgz#ae216d7f4f7e924d9a2e3ff1e4b1940220f9157b" + integrity sha512-ciYCResnLIATSsXuXnIOH4CbdfgV+H1Ltg16hJFN7/v6OxqnFr/IFGeLacaZ+fHLAm0TBbXwNK9/DNBzBUrO/g== -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cors@~2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" @@ -5008,9 +3383,9 @@ cors@~2.8.5: vary "^1" cosmiconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" - integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -5018,36 +3393,10 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== critters@0.0.12: version "0.0.12" @@ -5061,17 +3410,6 @@ critters@0.0.12: postcss "^8.3.7" pretty-bytes "^5.3.0" -critters@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.7.tgz#548b470360f4f3c51e622de3b7aa733c8f0b17bf" - integrity sha512-qUF2SaAWFYjNPdCcPpu68p2DnHiosia84yx5mPTlUMQjkjChR+n6sO1/I7yn2U2qNDgSPTd2SoaTIDQcUL+EwQ== - dependencies: - chalk "^4.1.0" - css "^3.0.0" - parse5 "^6.0.1" - parse5-htmlparser2-tree-adapter "^6.0.1" - pretty-bytes "^5.3.0" - cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -5083,23 +3421,6 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - css-blank-pseudo@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" @@ -5107,20 +3428,10 @@ css-blank-pseudo@^0.1.4: dependencies: postcss "^7.0.5" -css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= - -css-color-names@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-1.0.1.tgz#6ff7ee81a823ad46e020fa2fd6ab40a887e2ba67" - integrity sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA== - css-declaration-sorter@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.0.3.tgz#9dfd8ea0df4cc7846827876fafb52314890c21a9" - integrity sha512-52P95mvW1SMzuRZegvpluT6yEv0FqQusydKQPZsNN5Q7hh8EwQvN8E2nwuJ16BBvNN6LcoIZXu/Bk58DAhrrxw== + version "6.1.3" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz#e9852e4cf940ba79f509d9425b137d1f94438dc2" + integrity sha512-SvjQjNRZgh4ULK1LDJ2AduPKUKxIqmtU7ZAyi47BTV+M90Qvxr9AB6lKlLbDUfXqI9IQeYA8LbAsCZPpJEV3aA== dependencies: timsort "^0.3.0" @@ -5132,31 +3443,13 @@ css-has-pseudo@^0.10.0: postcss "^7.0.6" postcss-selector-parser "^5.0.0-rc.4" -css-line-break@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef" - integrity sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA== +css-line-break@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.0.1.tgz#3dc74c2ed5eb64211480281932475790243e7338" + integrity sha512-gwKYIMUn7xodIcb346wgUhE2Dt5O1Kmrc16PWi8sL4FTfyDj8P5095rzH7+O8CTZudJr+uw2GCI/hwEkDJFI2w== dependencies: base64-arraybuffer "^0.2.0" -css-loader@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.0.1.tgz#9e4de0d6636a6266a585bd0900b422c85539d25f" - integrity sha512-cXc2ti9V234cq7rJzFKhirb2L2iPy8ZjALeVJAozXYz9te3r4eqLSixNAbMDJSgJEQywqXzs8gonxaboeKqwiw== - dependencies: - camelcase "^6.2.0" - cssesc "^3.0.0" - icss-utils "^5.0.0" - loader-utils "^2.0.0" - postcss "^8.1.4" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^3.0.0" - semver "^7.3.2" - css-loader@6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.2.0.tgz#9663d9443841de957a3cb9bcea2eda65b3377071" @@ -5198,17 +3491,6 @@ css-prefers-color-scheme@^3.1.1: dependencies: postcss "^7.0.5" -css-select@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8" - integrity sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA== - dependencies: - boolbase "^1.0.0" - css-what "^4.0.0" - domhandler "^4.0.0" - domutils "^2.4.3" - nth-check "^2.0.0" - css-select@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" @@ -5244,11 +3526,6 @@ css-vendor@^2.0.8: "@babel/runtime" "^7.8.3" is-in-browser "^1.0.2" -css-what@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233" - integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A== - css-what@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" @@ -5264,15 +3541,6 @@ css@^2.0.0: source-map-resolve "^0.5.2" urix "^0.1.0" -css@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" - integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ== - dependencies: - inherits "^2.0.4" - source-map "^0.6.1" - source-map-resolve "^0.6.0" - cssauron@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" @@ -5295,41 +3563,6 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-default@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.1.tgz#5cd783caed942cc94159aeb10583af4691445b8c" - integrity sha512-kAhR71Tascmnjlhl4UegGA3KGGbMLXHkkqVpA9idsRT1JmIhIsz1C3tDpBeQMUw5EX5Rfb1HGc/PRqD2AFk3Vg== - dependencies: - css-declaration-sorter "^6.0.3" - cssnano-utils "^2.0.1" - postcss-calc "^8.0.0" - postcss-colormin "^5.1.1" - postcss-convert-values "^5.0.1" - postcss-discard-comments "^5.0.1" - postcss-discard-duplicates "^5.0.1" - postcss-discard-empty "^5.0.1" - postcss-discard-overridden "^5.0.1" - postcss-merge-longhand "^5.0.2" - postcss-merge-rules "^5.0.1" - postcss-minify-font-values "^5.0.1" - postcss-minify-gradients "^5.0.1" - postcss-minify-params "^5.0.1" - postcss-minify-selectors "^5.1.0" - postcss-normalize-charset "^5.0.1" - postcss-normalize-display-values "^5.0.1" - postcss-normalize-positions "^5.0.1" - postcss-normalize-repeat-style "^5.0.1" - postcss-normalize-string "^5.0.1" - postcss-normalize-timing-functions "^5.0.1" - postcss-normalize-unicode "^5.0.1" - postcss-normalize-url "^5.0.1" - postcss-normalize-whitespace "^5.0.1" - postcss-ordered-values "^5.0.1" - postcss-reduce-initial "^5.0.1" - postcss-reduce-transforms "^5.0.1" - postcss-svgo "^5.0.1" - postcss-unique-selectors "^5.0.1" - cssnano-preset-default@^5.1.8: version "5.1.8" resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.8.tgz#7525feb1b72f7b06e57f55064cbdae341d79dea2" @@ -5365,19 +3598,10 @@ cssnano-preset-default@^5.1.8: postcss-svgo "^5.0.3" postcss-unique-selectors "^5.0.2" -cssnano-utils@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2" - integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ== - -cssnano@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.2.tgz#3f6de4fd5ecb7b5fb636c1a606de5f38cd241493" - integrity sha512-8JK3EnPsjQsULme9/e5M2hF564f/480hwsdcHvQ7ZtAIMfQ1O3SCfs+b8Mjf5KJxhYApyRshR2QSovEJi2K72Q== - dependencies: - cosmiconfig "^7.0.0" - cssnano-preset-default "^5.0.1" - is-resolvable "^1.1.0" +cssnano-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2" + integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ== cssnano@^5.0.6: version "5.0.12" @@ -5397,29 +3621,24 @@ csso@^4.2.0: css-tree "^1.1.2" csstype@^2.5.2: - version "2.6.13" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f" - integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A== + version "2.6.19" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.19.tgz#feeb5aae89020bb389e1f63669a5ed490e391caa" + integrity sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ== csstype@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.3.tgz#2b410bbeba38ba9633353aff34b05d9755d065f8" - integrity sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag== + version "3.0.10" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" + integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= -cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - damerau-levenshtein@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791" - integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug== + version "1.0.7" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" + integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw== dashdash@^1.12.0: version "1.14.1" @@ -5428,10 +3647,10 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -date-fns@^2.21.3: - version "2.21.3" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.21.3.tgz#8f5f6889d7a96bbcc1f0ea50239b397a83357f9b" - integrity sha512-HeYdzCaFflc1i4tGbj7JKMjM4cKGYoyxwcIIkHzNgCkX8xXDNJDZXgDDVchIWpN4eQc3lH37WarduXFZJOtxfw== +date-fns@^2.26.0: + version "2.27.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.27.0.tgz#e1ff3c3ddbbab8a2eaadbb6106be2929a5a2d92b" + integrity sha512-sj+J0Mo2p2X1e306MHq282WS4/A8Pz/95GIFcsPNMPMZVI3EUrAdSv90al1k+p74WGLCruMXk23bfEDZa71X9Q== date-format@^2.1.0: version "2.1.0" @@ -5443,6 +3662,11 @@ date-format@^3.0.0: resolved "https://registry.yarnpkg.com/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95" integrity sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w== +dayjs@^1.10.4: + version "1.10.7" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" + integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== + debug@2.6.9, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -5450,10 +3674,10 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@4, debug@~4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@~4.3.1, debug@~4.3.2: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: ms "2.1.2" @@ -5464,34 +3688,13 @@ debug@4.3.2: dependencies: ms "2.1.2" -debug@^3.1.0, debug@^3.1.1: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^3.2.6: +debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" - integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== - dependencies: - ms "2.1.2" - -debug@^4.3.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -5606,11 +3809,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -delegate@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" - integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== - delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -5626,30 +3824,22 @@ dependency-graph@^0.11.0: resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= detect-node@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" - integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= -diff-match-patch@^1.0.4: +diff-match-patch@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== @@ -5659,15 +3849,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - dijkstrajs@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257" @@ -5680,10 +3861,10 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -directory-tree@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/directory-tree/-/directory-tree-2.2.4.tgz#6d5bd7d82e48378e256a1e87b678a43c50076e2e" - integrity sha512-2N43msQptKbi3WMfIs+U09yi6bfyKL+MWyj5VMj8t1F/Tx04bt1cn/EEIU3o1JBltlJk7NQnzOEuTNa/KQvbWA== +directory-tree@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/directory-tree/-/directory-tree-3.0.1.tgz#ce7e087d7a9a58947ab802125b4c45481270db72" + integrity sha512-IJL5L/zd73xbchfsIKMrhaRJCt28ek1UsS6LNZ6b9r7m+VbU1fd7JZAypn6gl1g4hpxn21QF3/scAWKIOMk4Ug== dns-equal@^1.0.0: version "1.0.0" @@ -5691,9 +3872,9 @@ dns-equal@^1.0.0: integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= dns-packet@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" - integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== dependencies: ip "^1.1.0" safe-buffer "^5.0.1" @@ -5706,14 +3887,14 @@ dns-txt@^2.0.2: buffer-indexof "^1.0.0" dom-align@^1.7.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.0.tgz#56fb7156df0b91099830364d2d48f88963f5a29c" - integrity sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA== + version "1.12.2" + resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.2.tgz#0f8164ebd0c9c21b0c790310493cd855892acd4b" + integrity sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg== dom-helpers@^5.0.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.0.tgz#57fd054c5f8f34c52a3eeffdb7e7e93cd357d95b" - integrity sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ== + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== dependencies: "@babel/runtime" "^7.8.7" csstype "^3.0.2" @@ -5737,36 +3918,17 @@ dom-serializer@^1.0.1: domhandler "^4.2.0" entities "^2.0.0" -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.2.tgz#f3b6e549201e46f588b59463dd77187131fe6971" - integrity sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA== - -domelementtype@^2.2.0: +domelementtype@^2.0.1, domelementtype@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== -domhandler@^4.0.0, domhandler@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059" - integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA== - dependencies: - domelementtype "^2.2.0" - -domutils@^2.4.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.6.0.tgz#2e15c04185d43fb16ae7057cb76433c6edb938b7" - integrity sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA== +domhandler@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" + integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== dependencies: - dom-serializer "^1.0.1" domelementtype "^2.2.0" - domhandler "^4.2.0" domutils@^2.6.0: version "2.8.0" @@ -5777,16 +3939,6 @@ domutils@^2.6.0: domelementtype "^2.2.0" domhandler "^4.2.0" -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -5810,33 +3962,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.571: - version "1.3.578" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.578.tgz#e6671936f4571a874eb26e2e833aa0b2c0b776e0" - integrity sha512-z4gU6dA1CbBJsAErW5swTGAaU2TBzc2mPAonJb00zqW1rOraDo2zfBMDRvaz9cVic+0JEZiYbHWPw/fTaZlG2Q== - -electron-to-chromium@^1.3.723: - version "1.3.737" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.737.tgz#196f2e9656f4f3c31930750e1899c091b72d36b5" - integrity sha512-P/B84AgUSQXaum7a8m11HUsYL8tj9h/Pt5f7Hg7Ty6bm5DxlFq+e5+ouHUoNQMsKDJ7u4yGfI8mOErCmSH9wyg== - electron-to-chromium@^1.3.896: - version "1.4.5" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.5.tgz#912e8fd1645edee2f0f212558f40916eb538b1f9" - integrity sha512-YKaB+t8ul5crdh6OeqT2qXdxJGI0fAYb6/X8pDIyye+c3a7ndOCk5gVeKX+ABwivCGNS56vOAif3TN0qJMpEHw== - -elliptic@^6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" - integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" + version "1.4.10" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.10.tgz#5f44ae6f6725b1949d6e8d34352f80d4c1880734" + integrity sha512-tFgA40Iq2oy4k2PnZrLJowbgpij+lD6ZLxkw8Ht1NKTYyN8dvSvC5xlo8X0WW2jqhKSzITrbr5mpB4/AZ/8OUA== emoji-regex@^7.0.1: version "7.0.3" @@ -5848,7 +3977,7 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-toolkit@^6.0.1: +emoji-toolkit@^6.5.0: version "6.6.0" resolved "https://registry.yarnpkg.com/emoji-toolkit/-/emoji-toolkit-6.6.0.tgz#e7287c43a96f940ec4c5428cd7100a40e57518f1" integrity sha512-pEu0kow2p1N8zCKnn/L6H0F3rWUBB3P3hVjr/O5yl1fK7N9jU4vO4G7EFapC5Y3XwZLUCY0FZbOPyTkH+4V2eQ== @@ -5858,6 +3987,11 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== +encode-utf8@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" + integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -5870,49 +4004,35 @@ encoding@^0.1.12: dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.0.0, end-of-stream@^1.1.0: +end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" -engine.io-parser@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-4.0.2.tgz#e41d0b3fb66f7bf4a3671d2038a154024edb501e" - integrity sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg== +engine.io-parser@~5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.2.tgz#69a2ec3ed431da021f0666712d07f106bcffa6ce" + integrity sha512-wuiO7qO/OEkPJSFueuATIXtrxF7/6GTbAO9QLv7nnbjwZ5tYhLm9zxvLwxstRs0dcT0KUlWTjtIOs1T86jt12g== dependencies: - base64-arraybuffer "0.1.4" + base64-arraybuffer "~1.0.1" -engine.io@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-4.1.1.tgz#9a8f8a5ac5a5ea316183c489bf7f5b6cf91ace5b" - integrity sha512-t2E9wLlssQjGw0nluF6aYyfX8LwYU8Jj0xct+pAhfWfv/YrBn6TSNtEYsgxHIfaMqfrLx07czcMg9bMN6di+3w== +engine.io@~6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.1.0.tgz#459eab0c3724899d7b63a20c3a6835cf92857939" + integrity sha512-ErhZOVu2xweCjEfYcTdkCnEYUiZgkAcBBAhW4jbIvNG8SLU3orAqoJCiytZjYF7eTpVmmCrLDjLIEaPlUAs1uw== dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" accepts "~1.3.4" base64id "2.0.0" cookie "~0.4.1" cors "~2.8.5" debug "~4.3.1" - engine.io-parser "~4.0.0" - ws "~7.4.2" - -enhanced-resolve@5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz#525c5d856680fbd5052de453ac83e32049958b5c" - integrity sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enhanced-resolve@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126" - integrity sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" + engine.io-parser "~5.0.0" + ws "~8.2.3" enhanced-resolve@^5.8.0, enhanced-resolve@^5.8.3: version "5.8.3" @@ -5928,9 +4048,9 @@ ent@~2.2.0: integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= entities@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" - integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== env-paths@^2.2.0: version "2.2.1" @@ -5942,10 +4062,10 @@ err-code@^2.0.2: resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== -errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== +errno@^0.1.1, errno@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== dependencies: prr "~1.0.1" @@ -5956,41 +4076,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: - version "1.17.7" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" - integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: - version "1.18.0-next.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" - integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - es-module-lexer@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.7.1.tgz#c2c8e0f46f2df06274cdaf0dd3f3b33e0a0b267d" @@ -6001,15 +4086,6 @@ es-module-lexer@^0.9.0: resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - es6-promise@^4.0.3: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -6135,11 +4211,6 @@ esbuild@0.13.8: esbuild-windows-64 "0.13.8" esbuild-windows-arm64 "0.13.8" -escalade@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" - integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -6163,20 +4234,12 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esrecurse@^4.1.0, esrecurse@^4.3.0: +esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== @@ -6189,9 +4252,9 @@ estraverse@^4.1.1: integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" @@ -6218,31 +4281,18 @@ eventemitter3@^4.0.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" - integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== - events@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== eventsource@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" - integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" + integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== dependencies: original "^1.0.0" -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -6359,28 +4409,16 @@ extsprintf@1.3.0: integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.1.1, fast-glob@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" - integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - -fast-glob@^3.2.5: +fast-glob@^3.1.1, fast-glob@^3.2.5: version "3.2.7" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== @@ -6402,9 +4440,9 @@ fastparse@^1.1.2: integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== fastq@^1.6.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" - integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== dependencies: reusify "^1.0.4" @@ -6415,11 +4453,6 @@ faye-websocket@^0.11.3: dependencies: websocket-driver ">=0.5.1" -figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== - figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -6427,20 +4460,12 @@ figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" -file-loader@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" - integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -file-selector@^0.1.12: - version "0.1.13" - resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.1.13.tgz#5efd977ca2bca1700992df1b10e254f4e73d2df4" - integrity sha512-T2efCBY6Ps+jLIWdNQsmzt/UnAjKOEAlsZVdnQztg/BtAZGNL4uX1Jet9cMM8gify/x4CSudreji2HssGBNVIQ== +file-selector@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.2.4.tgz#7b98286f9dbb9925f420130ea5ed0a69238d4d80" + integrity sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA== dependencies: - tslib "^2.0.1" + tslib "^2.0.3" file-uri-to-path@1.0.0: version "1.0.0" @@ -6477,7 +4502,7 @@ finalhandler@1.1.2, finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-cache-dir@3.3.1, find-cache-dir@^3.3.1: +find-cache-dir@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== @@ -6486,14 +4511,14 @@ find-cache-dir@3.3.1, find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== dependencies: commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" + make-dir "^3.0.2" + pkg-dir "^4.1.0" find-up@^3.0.0: version "3.0.0" @@ -6535,18 +4560,10 @@ flatten@^1.0.2: version "0.9.0-alpha" resolved "git://github.com/thingsboard/flot.git#0ff0c775db7c74e705f6c3c2bba92080a202ccd4" -flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - follow-redirects@^1.0.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" - integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + version "1.14.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381" + integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA== font-awesome@^4.7.0: version "4.7.0" @@ -6572,15 +4589,10 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - -fraction.js@^4.0.13: - version "4.1.1" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff" - integrity sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg== +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fragment-cache@^0.2.1: version "0.2.1" @@ -6594,14 +4606,6 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -6632,16 +4636,6 @@ fs-monkey@1.0.3: resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -6655,12 +4649,7 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== - -fsevents@~2.3.1, fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -6684,11 +4673,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -6710,6 +4694,15 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-intrinsic@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -6737,13 +4730,6 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== - dependencies: - is-glob "^4.0.1" - glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -6763,10 +4749,10 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@7.1.6, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -6775,10 +4761,10 @@ glob@7.1.6, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glo once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== +glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -6792,18 +4778,6 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globby@^11.0.1: - version "11.0.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" - integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - globby@^11.0.3: version "11.0.4" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" @@ -6839,22 +4813,10 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" -good-listener@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" - integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= - dependencies: - delegate "^3.1.2" - -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== - -graceful-fs@^4.2.3: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== hammerjs@^2.0.8: version "2.0.8" @@ -6896,10 +4858,17 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" has-unicode@^2.0.0: version "2.0.1" @@ -6944,23 +4913,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - hdr-histogram-js@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/hdr-histogram-js/-/hdr-histogram-js-2.0.1.tgz#ecb1ff2bcb6181c3e93ff4af9472c28c7e97284e" @@ -6975,20 +4927,6 @@ hdr-histogram-percentiles-obj@^3.0.0: resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c" integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw== -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -6996,13 +4934,6 @@ hoist-non-react-statics@^3.3.2: dependencies: react-is "^16.7.0" -hosted-git-info@^3.0.2: - version "3.0.5" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.5.tgz#bea87905ef7317442e8df3087faa3c842397df03" - integrity sha512-i4dpK6xj9BIpVOTboXIlKG9+8HMKggcrMX7WA24xZtKwX0TPelq/rbaS5rCKeNX8sJXZJGdSxpnEGtta+wismQ== - dependencies: - lru-cache "^6.0.0" - hosted-git-info@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" @@ -7020,32 +4951,23 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= - html-entities@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" - integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -html2canvas@^1.0.0-rc.7: - version "1.0.0-rc.7" - resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.0.0-rc.7.tgz#70c159ce0e63954a91169531894d08ad5627ac98" - integrity sha512-yvPNZGejB2KOyKleZspjK/NruXVQuowu8NnV2HYG7gW7ytzl+umffbtUI62v2dCHQLDdsK6HIDtyJZ0W3neerA== +html2canvas@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.3.3.tgz#f01531f9bf7c73a771c5ee73b4a5cab6576bf876" + integrity sha512-nQi0ayEY1cMiUMbq/F5hRwMAqsRMo7NIP6VaCqaXnXO6b/FfZO49oSfIJjdyRha28EuY8D6FBCzQOXPQV0TCrA== dependencies: - css-line-break "1.1.1" + css-line-break "2.0.1" + text-segmentation "^1.0.2" http-cache-semantics@^4.1.0: version "4.1.0" @@ -7090,9 +5012,9 @@ http-errors@~1.7.2: toidentifier "1.0.0" http-parser-js@>=0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.2.tgz#da2e31d237b393aae72ace43882dd7e270a8ff77" - integrity sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ== + version "0.5.5" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5" + integrity sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA== http-proxy-agent@^4.0.1: version "4.0.1" @@ -7131,11 +5053,6 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" @@ -7171,10 +5088,10 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" - integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== +iconv-lite@^0.6.2, iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" @@ -7188,16 +5105,6 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - ignore-walk@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" @@ -7206,9 +5113,9 @@ ignore-walk@^3.0.3: minimatch "^3.0.4" ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + version "5.1.9" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" + integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== image-size@~0.5.0: version "0.5.5" @@ -7241,13 +5148,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indefinite-observable@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/indefinite-observable/-/indefinite-observable-2.0.1.tgz#574af29bfbc17eb5947793797bddc94c9d859400" - integrity sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ== - dependencies: - symbol-observable "1.2.0" - indent-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" @@ -7258,7 +5158,7 @@ indexes-of@^1.0.1: resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= -infer-owner@^1.0.3, infer-owner@^1.0.4: +infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== @@ -7271,16 +5171,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -7292,28 +5187,9 @@ ini@2.0.0: integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== ini@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -inquirer@7.3.3: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== inquirer@8.1.2: version "8.1.2" @@ -7378,9 +5254,12 @@ is-accessor-descriptor@^1.0.0: kind-of "^6.0.0" is-arguments@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" - integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-arrayish@^0.2.1: version "0.2.1" @@ -7406,11 +5285,6 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4, is-callable@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" - integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== - is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -7418,18 +5292,6 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-color-stop@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - is-core-module@^2.2.0: version "2.8.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" @@ -7452,9 +5314,11 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-descriptor@^0.1.0: version "0.1.6" @@ -7474,12 +5338,7 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-docker@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" - integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== - -is-docker@^2.1.1: +is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== @@ -7525,14 +5384,7 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -7554,11 +5406,6 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= -is-negative-zero@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" - integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -7616,12 +5463,13 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-regex@^1.0.4, is-regex@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" - integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== +is-regex@^1.0.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: - has-symbols "^1.0.1" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-resolvable@^1.1.0: version "1.1.0" @@ -7633,13 +5481,6 @@ is-stream@^1.1.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -7672,20 +5513,15 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: +isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= -isarray@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isbinaryfile@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.6.tgz#edcb62b224e2b4710830b67498c8e4e5a4d2610b" - integrity sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg== +isbinaryfile@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf" + integrity sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w== isexe@^2.0.0: version "2.0.0" @@ -7715,9 +5551,9 @@ istanbul-lib-coverage@^2.0.5: integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== istanbul-lib-instrument@^4.0.3: version "4.0.3" @@ -7750,28 +5586,23 @@ istanbul-lib-source-maps@^3.0.6: source-map "^0.6.1" istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + version "3.1.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.1.tgz#7085857f17d2441053c6ce5c3b8fdf6882289397" + integrity sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jasmine-core@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.6.0.tgz#491f3bb23941799c353ceb7a45b38a950ebc5a20" - integrity sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw== +jasmine-core@^3.6.0, jasmine-core@~3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.10.1.tgz#7aa6fa2b834a522315c651a128d940eca553989a" + integrity sha512-ooZWSDVAdh79Rrj4/nnfklL3NQVra0BcuhcuWoAwwi+znLDoUeH87AFfeX8s+YeYi6xlv5nveRyaA1v7CintfA== jasmine-core@~2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= -jasmine-core@~3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.7.1.tgz#0401327f6249eac993d47bbfa18d4e8efacfb561" - integrity sha512-DH3oYDS/AUvvr22+xUBW62m1Xoy7tUlY1tsxKEJvl5JeJ7q8zd1K5bUwiOxdH+erj6l2vAMM3hV25Xs9/WrmuQ== - jasmine-spec-reporter@~7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz#94b939448e63d4e2bd01668142389f20f0a8ea49" @@ -7793,53 +5624,43 @@ jasminewd2@^2.1.0: resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= -jest-worker@26.6.2, jest-worker@^26.5.0: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - jest-worker@^27.0.2, jest-worker@^27.0.6: - version "27.4.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.0.tgz#fa10dddc611cbb47a4153543dd16a0c7e7fd745c" - integrity sha512-4WuKcUxtzxBoKOUFbt1MtTY9fJwPVD4aN/4Cgxee7OLetPZn5as2bjfZz98XSf2Zq1JFfhqPZpS+43BmWXKgCA== + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.2.tgz#0fb123d50955af1a450267787f340a1bf7e12bc4" + integrity sha512-0QMy/zPovLfUPyHuOuuU4E+kGACXXE84nRnq6lBVI9GJg5DCBiA97SATi+ZP8CpiJwEQy1oCPjRBf8AnLjN+Ag== dependencies: "@types/node" "*" merge-stream "^2.0.0" supports-color "^8.0.0" -jquery.terminal@^2.24.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/jquery.terminal/-/jquery.terminal-2.24.0.tgz#779a92b4478ac7542e7adaf5e17f4d4d92fd622c" - integrity sha512-rtjTBj7/FYoBiWawiNTYNXIRqVI4n39WF/x1h/bEKFb48Rzgr4/dpkKGd1dgZau714ewzczAi7CEBTKvhM6RjA== +jquery.terminal@^2.29.4: + version "2.29.4" + resolved "https://registry.yarnpkg.com/jquery.terminal/-/jquery.terminal-2.29.4.tgz#0403942e3f68a23d54ba9ad7c592f1da2b2829cd" + integrity sha512-ugzctBbbJmw3ZGIhYziBFEK8QnWAZy2q6sZUtmPgjni4ILg59tO0WJI9DkKiDZ4LQtdCVexQ5oP0J90jMN+TzA== dependencies: - "@types/jquery" "^3.5.5" + "@jcubic/lily" "^0.3.0" + "@types/jquery" "^3.5.6" + ansidec "^0.3.4" + iconv-lite "^0.6.3" jquery "^3.6.0" - prismjs "^1.23.0" + prismjs "^1.25.0" wcwidth "^1.0.1" + optionalDependencies: + fsevents "^2.3.2" -jquery@>=1.9.1, jquery@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5" - integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg== - -jquery@^3.6.0: +jquery@>=1.9.1, jquery@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== -js-beautify@^1.13.13: - version "1.13.13" - resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.13.13.tgz#756907d1728f329f2b84c42efd56ad17514620bf" - integrity sha512-oH+nc0U5mOAqX8M5JO1J0Pw/7Q35sAdOsM5W3i87pir9Ntx6P/5Gx1xLNoK+MGyvHk4rqqRCE4Oq58H6xl2W7A== +js-beautify@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.14.0.tgz#2ce790c555d53ce1e3d7363227acf5dc69024c2d" + integrity sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ== dependencies: config-chain "^1.1.12" editorconfig "^0.15.3" glob "^7.1.3" - mkdirp "^1.0.4" nopt "^5.0.0" "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: @@ -7848,9 +5669,9 @@ js-beautify@^1.13.13: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -7897,10 +5718,10 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== json-stringify-safe@~5.0.1: version "5.0.1" @@ -7920,9 +5741,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== dependencies: minimist "^1.2.5" @@ -7944,83 +5765,82 @@ jsonparse@^1.3.1: integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== dependencies: assert-plus "1.0.0" extsprintf "1.3.0" - json-schema "0.2.3" + json-schema "0.4.0" verror "1.10.0" jss-plugin-camel-case@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.6.0.tgz#93d2cd704bf0c4af70cc40fb52d74b8a2554b170" - integrity sha512-JdLpA3aI/npwj3nDMKk308pvnhoSzkW3PXlbgHAzfx0yHWnPPVUjPhXFtLJzgKZge8lsfkUxvYSQ3X2OYIFU6A== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz#8d7f915c8115afaff8cbde08faf610ec9892fba6" + integrity sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA== dependencies: "@babel/runtime" "^7.3.1" hyphenate-style-name "^1.0.3" - jss "10.6.0" + jss "10.8.2" jss-plugin-default-unit@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.6.0.tgz#af47972486819b375f0f3a9e0213403a84b5ef3b" - integrity sha512-7y4cAScMHAxvslBK2JRK37ES9UT0YfTIXWgzUWD5euvR+JR3q+o8sQKzBw7GmkQRfZijrRJKNTiSt1PBsLI9/w== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz#c66f12e02e0815d911b85c02c2a979ee7b4ce69a" + integrity sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" jss-plugin-global@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.6.0.tgz#3e8011f760f399cbadcca7f10a485b729c50e3ed" - integrity sha512-I3w7ji/UXPi3VuWrTCbHG9rVCgB4yoBQLehGDTmsnDfXQb3r1l3WIdcO8JFp9m0YMmyy2CU7UOV6oPI7/Tmu+w== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz#1a35632a693cf50113bcc5ffe6b51969df79c4ec" + integrity sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" jss-plugin-nested@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.6.0.tgz#5f83c5c337d3b38004834e8426957715a0251641" - integrity sha512-fOFQWgd98H89E6aJSNkEh2fAXquC9aZcAVjSw4q4RoQ9gU++emg18encR4AT4OOIFl4lQwt5nEyBBRn9V1Rk8g== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz#79f3c7f75ea6a36ae72fe52e777035bb24d230c7" + integrity sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" tiny-warning "^1.0.2" jss-plugin-props-sort@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.6.0.tgz#297879f35f9fe21196448579fee37bcde28ce6bc" - integrity sha512-oMCe7hgho2FllNc60d9VAfdtMrZPo9n1Iu6RNa+3p9n0Bkvnv/XX5San8fTPujrTBScPqv9mOE0nWVvIaohNuw== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz#e25a7471868652c394562b6dc5433dcaea7dff6f" + integrity sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" jss-plugin-rule-value-function@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.6.0.tgz#3c1a557236a139d0151e70a82c810ccce1c1c5ea" - integrity sha512-TKFqhRTDHN1QrPTMYRlIQUOC2FFQb271+AbnetURKlGvRl/eWLswcgHQajwuxI464uZk91sPiTtdGi7r7XaWfA== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz#55354b55f1b2968a15976729968f767f02d64049" + integrity sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" tiny-warning "^1.0.2" jss-plugin-vendor-prefixer@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.6.0.tgz#e1fcd499352846890c38085b11dbd7aa1c4f2c78" - integrity sha512-doJ7MouBXT1lypLLctCwb4nJ6lDYqrTfVS3LtXgox42Xz0gXusXIIDboeh6UwnSmox90QpVnub7au8ybrb0krQ== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz#ebb4a482642f34091e454901e21176441dd5f475" + integrity sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg== dependencies: "@babel/runtime" "^7.3.1" css-vendor "^2.0.8" - jss "10.6.0" + jss "10.8.2" -jss@10.6.0, jss@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss/-/jss-10.6.0.tgz#d92ff9d0f214f65ca1718591b68e107be4774149" - integrity sha512-n7SHdCozmxnzYGXBHe0NsO0eUf9TvsHVq2MXvi4JmTn3x5raynodDVE/9VQmBdWFyyj9HpHZ2B4xNZ7MMy7lkw== +jss@10.8.2, jss@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss/-/jss-10.8.2.tgz#4b2a30b094b924629a64928236017a52c7c97505" + integrity sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ== dependencies: "@babel/runtime" "^7.3.1" csstype "^3.0.2" - indefinite-observable "^2.0.1" is-in-browser "^1.1.3" tiny-warning "^1.0.2" @@ -8031,27 +5851,17 @@ jstree-bootstrap-theme@^1.0.1: dependencies: jquery ">=1.9.1" -jstree@^3.3.11: - version "3.3.11" - resolved "https://registry.yarnpkg.com/jstree/-/jstree-3.3.11.tgz#da2f12bcab6af61839586c81db46e8f2e19160aa" - integrity sha512-9ZJKroPjCyjb6JLPuAbBrLJKT6pS1f4m5gkwoEagG5oQWtvzm0IiDsntXTxeFtz7AmqrKfij+gLfF9MgWriNxg== +jstree@^3.3.12: + version "3.3.12" + resolved "https://registry.yarnpkg.com/jstree/-/jstree-3.3.12.tgz#cf206bc85dcf4a4664ed6617eaae3bd5983d8601" + integrity sha512-vHNLWkUr02ZYH7RcIckvhtLUtneWCVEtIKpIp2G9WtRh01ITv18EoNtNQcFG3ozM+oK6wp1Z300gSLXNQWCqGA== dependencies: jquery ">=1.9.1" -jszip@^3.1.3: - version "3.5.0" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6" - integrity sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA== - dependencies: - lie "~3.3.0" - pako "~1.0.2" - readable-stream "~2.3.6" - set-immediate-shim "~1.0.1" - -jszip@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.6.0.tgz#839b72812e3f97819cc13ac4134ffced95dd6af9" - integrity sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ== +jszip@^3.1.3, jszip@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9" + integrity sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg== dependencies: lie "~3.3.0" pako "~1.0.2" @@ -8076,12 +5886,12 @@ karma-coverage-istanbul-reporter@~3.0.3: istanbul-reports "^3.0.2" minimatch "^3.0.4" -karma-jasmine-html-reporter@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.6.0.tgz#586e17025a1b4128e9fba55d5f1e8921bfc3bc1e" - integrity sha512-ELO9yf0cNqpzaNLsfFgXd/wxZVYkE2+ECUwhMHUD4PZ17kcsPsYsVyjquiRqyMn2jkd2sHt0IeMyAyq1MC23Fw== +karma-jasmine-html-reporter@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz#52c489a74d760934a1089bfa5ea4a8fcb84cc28b" + integrity sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ== -karma-jasmine@~4.0.0: +karma-jasmine@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-4.0.1.tgz#b99e073b6d99a5196fc4bffc121b89313b0abd82" integrity sha512-h8XDAhTiZjJKzfkoO1laMH+zfNlra+dEQHUAjpn5JV1zCPtOIVWGQjLBrqhnzQa/hrU2XrZwSyBa6XjEBzfXzw== @@ -8095,41 +5905,41 @@ karma-source-map-support@1.4.0: dependencies: source-map-support "^0.5.5" -karma@~6.3.2: - version "6.3.2" - resolved "https://registry.yarnpkg.com/karma/-/karma-6.3.2.tgz#24b62fbae3e8b5218cc32a0dac49ad08a541e76d" - integrity sha512-fo4Wt0S99/8vylZMxNj4cBFyOBBnC1bewZ0QOlePij/2SZVWxqbyLeIddY13q6URa2EpLRW8ixvFRUMjkmo1bw== +karma@~6.3.9: + version "6.3.9" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.3.9.tgz#cc309607f0fcdb58a88643184f3e4ba8bff26751" + integrity sha512-E/MqdLM9uVIhfuyVnrhlGBu4miafBdXEAEqCmwdEMh3n17C7UWC/8Kvm3AYKr91gc7scutekZ0xv6rxRaUCtnw== dependencies: body-parser "^1.19.0" braces "^3.0.2" - chokidar "^3.4.2" + chokidar "^3.5.1" colors "^1.4.0" connect "^3.7.0" di "^0.0.1" dom-serialize "^2.2.1" - glob "^7.1.6" - graceful-fs "^4.2.4" + glob "^7.1.7" + graceful-fs "^4.2.6" http-proxy "^1.18.1" - isbinaryfile "^4.0.6" - lodash "^4.17.19" - log4js "^6.2.1" - mime "^2.4.5" + isbinaryfile "^4.0.8" + lodash "^4.17.21" + log4js "^6.3.0" + mime "^2.5.2" minimatch "^3.0.4" qjobs "^1.2.0" range-parser "^1.2.1" rimraf "^3.0.2" - socket.io "^3.1.0" + socket.io "^4.2.0" source-map "^0.6.1" - tmp "0.2.1" - ua-parser-js "^0.7.23" + tmp "^0.2.1" + ua-parser-js "^0.7.30" yargs "^16.1.1" katex@^0.13.0: - version "0.13.18" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.13.18.tgz#ba89e8e4b70cc2325e25e019a62b9fe71e5c2931" - integrity sha512-a3dC4NSVSDU3O1WZbTnOiA8rVNJ2lSiomOl0kmckCIGObccIHXof7gAseIY0o1gjEspe+34ZeSEX2D1ChFKIvA== + version "0.13.24" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.13.24.tgz#fe55455eb455698cb24b911a353d16a3c855d905" + integrity sha512-jZxYuKCma3VS5UuxOx/rFV1QyGSl3Uy/i0kTJF3HgQ5xMinCQVF8Zd4bMY/9aI9b9A2pjIBOsjSSm68ykTAr8w== dependencies: - commander "^6.0.0" + commander "^8.0.0" killable@^1.0.1: version "1.0.1" @@ -8168,9 +5978,9 @@ klaw-sync@^6.0.0: graceful-fs "^4.1.11" klona@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" - integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== + version "2.0.5" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" + integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== leaflet-polylinedecorator@^1.6.0: version "1.6.0" @@ -8211,15 +6021,6 @@ less-loader@10.0.1: dependencies: klona "^2.0.4" -less-loader@7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-7.3.0.tgz#f9d6d36d18739d642067a05fb5bd70c8c61317e5" - integrity sha512-Mi8915g7NMaLlgi77mgTTQvK022xKRQBIVDSyfl3ErTuBhmZBQab0mjeJjNNqGbdR+qrfTleKXqbGI4uEFavxg== - dependencies: - klona "^2.0.4" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - less@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/less/-/less-4.1.1.tgz#15bf253a9939791dc690888c3ff424f3e6c7edba" @@ -8237,14 +6038,6 @@ less@4.1.1: needle "^2.5.2" source-map "~0.6.0" -license-webpack-plugin@2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.11.tgz#0d93188a31fce350a44c86212badbaf33dcd29d8" - integrity sha512-0iVGoX5vx0WDy8dmwTTpOOMYiGqILyUbDeVMFH52AjgBlS58lHwOlFMSoqg5nY8Kxl6+FRKyUZY/UdlQaOyqDw== - dependencies: - "@types/webpack-sources" "^0.1.5" - webpack-sources "^1.2.0" - license-webpack-plugin@2.3.20: version "2.3.20" resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.20.tgz#f51fb674ca31519dbedbe1c7aabc036e5a7f2858" @@ -8266,21 +6059,16 @@ lilconfig@^2.0.3: integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - -loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== loader-runner@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@2.0.0, loader-utils@^2.0.0: +loader-utils@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== @@ -8289,7 +6077,7 @@ loader-utils@2.0.0, loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" -loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: +loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== @@ -8298,6 +6086,15 @@ loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: emojis-list "^3.0.0" json5 "^1.0.1" +loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -8338,18 +6135,11 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@~4.17.21: +lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21, lodash@~4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" - integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== - dependencies: - chalk "^4.0.0" - log-symbols@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" @@ -8358,7 +6148,7 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -log4js@^6.2.1: +log4js@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" integrity sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw== @@ -8370,11 +6160,11 @@ log4js@^6.2.1: streamroller "^2.2.4" loglevel@^1.6.8: - version "1.7.0" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0" - integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ== + version "1.8.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" + integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -8389,13 +6179,6 @@ lru-cache@^4.1.5: pseudomap "^1.0.2" yallist "^2.1.2" -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -8410,7 +6193,7 @@ magic-string@0.25.7, magic-string@^0.25.0: dependencies: sourcemap-codec "^1.4.4" -make-dir@^2.0.0, make-dir@^2.1.0: +make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -8488,15 +6271,6 @@ material-design-icons@^3.0.1: resolved "https://registry.yarnpkg.com/material-design-icons/-/material-design-icons-3.0.1.tgz#9a71c48747218ebca51e51a66da682038cdcb7bf" integrity sha1-mnHEh0chjrylHlGmbaaCA4zct78= -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -8530,14 +6304,6 @@ memory-fs@^0.4.1: errno "^0.1.3" readable-stream "^2.0.1" -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -8603,15 +6369,7 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -micromatch@^4.0.4: +micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== @@ -8619,37 +6377,12 @@ micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-db@1.51.0: +mime-db@1.51.0, "mime-db@>= 1.43.0 < 2": version "1.51.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== -"mime-db@>= 1.43.0 < 2": - version "1.45.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" - integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== - -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== - dependencies: - mime-db "1.44.0" - -mime-types@^2.1.27, mime-types@^2.1.31: +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.34" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== @@ -8661,10 +6394,10 @@ mime@1.6.0, mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.4.4, mime@^2.4.5: - version "2.4.6" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" - integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== +mime@^2.4.4, mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== mimic-fn@^2.1.0: version "2.1.0" @@ -8676,15 +6409,6 @@ mimic-fn@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== -mini-css-extract-plugin@1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.5.tgz#252166e78879c106e0130f229d44e0cbdfcebed3" - integrity sha512-tvmzcwqJJXau4OQE5vT72pRT18o2zF+tQJp8CWchqvfQnTlflkzS+dANYcRdyPRWUWRkfmeNTKltx0NZI/b5dQ== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - webpack-sources "^1.1.0" - mini-css-extract-plugin@2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.2.tgz#b3508191ea479388a4715018c99dd3e6dd40d2d2" @@ -8692,16 +6416,11 @@ mini-css-extract-plugin@2.4.2: dependencies: schema-utils "^3.1.0" -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: +minimalistic-assert@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -8722,9 +6441,9 @@ minipass-collect@^1.0.2: minipass "^3.0.0" minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.3.3.tgz#34c7cea038c817a8658461bf35174551dce17a0a" - integrity sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ== + version "1.4.1" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== dependencies: minipass "^3.1.0" minipass-sized "^1.0.3" @@ -8762,9 +6481,9 @@ minipass-sized@^1.0.3: minipass "^3.0.0" minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" - integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== + version "3.1.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" + integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== dependencies: yallist "^4.0.0" @@ -8776,22 +6495,6 @@ minizlib@^2.0.0, minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -8812,17 +6515,10 @@ mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -moment-timezone@*: - version "0.5.31" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.31.tgz#9c40d8c5026f0c7ab46eda3d63e49c155148de05" - integrity sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA== - dependencies: - moment ">= 2.9.0" - -moment-timezone@^0.5.33: - version "0.5.33" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.33.tgz#b252fd6bb57f341c9b59a5ab61a8e51a73bbd22c" - integrity sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w== +moment-timezone@*, moment-timezone@^0.5.34: + version "0.5.34" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c" + integrity sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg== dependencies: moment ">= 2.9.0" @@ -8831,28 +6527,11 @@ moment-timezone@^0.5.33: resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== -mousetrap@1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.3.tgz#80fee49665fd478bccf072c9d46bdf1bfed3558a" - integrity sha512-bd+nzwhhs9ifsUrC2tWaSgm24/oo2c83zaRyZQF06hYA6sANfsXHtnZ19AbbbDXCDzeH5nZBSQ4NvCjgD62tJA== - mousetrap@^1.6.0: version "1.6.5" resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.5.tgz#8a766d8c272b08393d5f56074e0b5ec183485bf9" integrity sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA== -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -8863,11 +6542,16 @@ ms@2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@2.1.2, ms@^2.0.0, ms@^2.1.1: +ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.0.0, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -8887,16 +6571,11 @@ mute-stream@0.0.8: integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== nan@^2.12.1: - version "2.14.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" - integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== -nanoid@^3.1.22, nanoid@^3.1.23: - version "3.1.23" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" - integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== - -nanoid@^3.1.30: +nanoid@^3.1.23, nanoid@^3.1.30: version "3.1.30" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== @@ -8919,9 +6598,9 @@ nanomatch@^1.2.9: to-regex "^3.0.1" needle@^2.5.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.6.0.tgz#24dbb55f2509e2324b4a99d61f413982013ccdbe" - integrity sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg== + version "2.9.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" + integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== dependencies: debug "^3.2.6" iconv-lite "^0.4.4" @@ -8932,7 +6611,7 @@ negotiator@0.6.2, negotiator@^0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: +neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -8944,12 +6623,12 @@ ngrx-store-freeze@^0.2.4: dependencies: deep-freeze-strict "^1.1.1" -ngx-clipboard@^14.0.1: - version "14.0.1" - resolved "https://registry.yarnpkg.com/ngx-clipboard/-/ngx-clipboard-14.0.1.tgz#fe977ee115f50f6a589487f6f99fa5eef5203763" - integrity sha512-y6fDrvAso1cbM+VvHgB2kJ3dcQ/EBPol33nLaqqKB1jNO/Kd3l17EHdXNW/oKY0wUKCHk7ZCuiinREgUHEYfXg== +ngx-clipboard@^14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/ngx-clipboard/-/ngx-clipboard-14.0.2.tgz#4098b32499a75a41f8c05991f36d30d2a8ec8122" + integrity sha512-zJaFi09D2bq9X1RYvFixE0AfYOI7E8mUO8S0GXcq76HisuE816HRl+8A46G+NML5GPA3Lr5qaGnQJN533So+8g== dependencies: - ngx-window-token ">=4.0.0" + ngx-window-token ">=4.0.0 <6.0.0" tslib "^2.0.0" ngx-color-picker@^11.0.0: @@ -8959,12 +6638,13 @@ ngx-color-picker@^11.0.0: dependencies: tslib "^2.0.0" -ngx-daterangepicker-material@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/ngx-daterangepicker-material/-/ngx-daterangepicker-material-4.0.1.tgz#788c2e32eb4717629d4a0e60a60bf8d6430d8c13" - integrity sha512-0gY6DGU+dgYdmoAKrIJSB9xnDqBvj91Yis3II/ZJxxMfZVTG4qMMatck6w8FzdU+CYT64ArCq+Uwa6hJRHX6Nw== +ngx-daterangepicker-material@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ngx-daterangepicker-material/-/ngx-daterangepicker-material-5.0.1.tgz#57403e605b4c317e6f694e3b289732945fcd7e97" + integrity sha512-vbxsiRqyBgXExRBPxuCodLlOOsVEZJ20nTPZks/7z943gZcb2XKwRuQ9hi43MG0xl7RVzDKZdsNKU8bzB86g7g== dependencies: - tslib "^1.10.0" + dayjs "^1.10.4" + tslib "^2.0.0" ngx-drag-drop@^2.0.0: version "2.0.0" @@ -8979,41 +6659,42 @@ ngx-drag-drop@^2.0.0: dependencies: tslib "^1.13.0" -ngx-hm-carousel@^2.0.0-rc.1: - version "2.0.0-rc.1" - resolved "https://registry.yarnpkg.com/ngx-hm-carousel/-/ngx-hm-carousel-2.0.0-rc.1.tgz#0ca7663da21a9ac60470b37d300637c29dc64b3a" - integrity sha512-vEMMFctBpQ+0hiwLo97IVmk39He9Gx2Xp6CudD5K1y4xxsuAkpqsGO5jh3KG3i2kMjP8OZY6plTJwIcATvBmLg== +ngx-hm-carousel@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ngx-hm-carousel/-/ngx-hm-carousel-2.0.1.tgz#29574c5128b26d8520b1ef6499eec7efca4e403f" + integrity sha512-iZxe1SVDkmXsSdZlU5nOtYV7hZGiRTEOij7Esnmc+PVgmMmIZe784uZv1RM/cKb3+hNesHjJuYyyNDkD+ryANw== dependencies: + "@types/hammerjs" "^2.0.39" hammerjs "^2.0.8" - resize-observer-polyfill "^1.5.1" + tslib "^2.0.0" -ngx-markdown@^11.1.3: - version "11.1.3" - resolved "https://registry.yarnpkg.com/ngx-markdown/-/ngx-markdown-11.1.3.tgz#4d01c2dc425e5a46d1b6aa8517d9a1c1feaa1efd" - integrity sha512-z32q8l76ubrcP62L03mdvrizwueLBHV10LkT8MEDnFcjmY+8J1PytxFJ9EBTJpvc+CaPolgAoi7felN2XJZTSg== +ngx-markdown@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/ngx-markdown/-/ngx-markdown-12.0.1.tgz#94345e99176533c17396f93e97ff5dc172d8ebcc" + integrity sha512-vMp9SyqmVQZCX374MiCV4sRR1SIv5m3xR2HZ39b3+6/BGjAb46mb4wRXKdIxYUoPba7NYZ8GAt5moUCyVZcCyA== dependencies: "@types/marked" "^2.0.0" - emoji-toolkit "^6.0.1" + emoji-toolkit "^6.5.0" katex "^0.13.0" marked "^2.0.0" prismjs "^1.23.0" - tslib "^2.0.0" + tslib "^2.1.0" -ngx-sharebuttons@^8.0.5: - version "8.0.5" - resolved "https://registry.yarnpkg.com/ngx-sharebuttons/-/ngx-sharebuttons-8.0.5.tgz#49481fcb8bf9541747fd72093eca6f4777c1d371" - integrity sha512-LAaZQk1i/yuYkX+SK72OkJBMNmGJ7SS/yoGEIyuUd7r9F9SwLpWfUAjccmtuM0qDzd48h+1CCnPGIB6WYlKY4g== +ngx-sharebuttons@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/ngx-sharebuttons/-/ngx-sharebuttons-9.0.0.tgz#6919ecb2c77ce6165b443cbc7c44884500186173" + integrity sha512-suoDgXnJwn2EHJzFDvm54KUnW6pGq+APC7VT54HNndwp1lcwXj5QbFgB5Vlk4IfN9VIBOE+IAwdFEdxmIK73Og== dependencies: tslib "^2.0.0" -ngx-translate-messageformat-compiler@^4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/ngx-translate-messageformat-compiler/-/ngx-translate-messageformat-compiler-4.9.0.tgz#00c3d34f7ed2bed6b406acb2e67b7b8989194430" - integrity sha512-Bat3CjtP7SJ8ks9z3GASW/0wjikf/vE9Vqb0H9SmOgP22CNb22K2oMdPacQQOBjy2hRvcVQ+GDqk5oa7MKiw/A== +ngx-translate-messageformat-compiler@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/ngx-translate-messageformat-compiler/-/ngx-translate-messageformat-compiler-4.11.0.tgz#c9b71dd139ba5fcdcd809001e22622de589fd707" + integrity sha512-OdGfWV4fF3DhZqGIHcLmOnQDufugmZ+E90NYr1UPGRZgT10lilr9oLmIrisy3lW4THnZFNo9JXsX7+fX84LbDw== dependencies: tslib "^1.10.0" -ngx-window-token@>=4.0.0: +"ngx-window-token@>=4.0.0 <6.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/ngx-window-token/-/ngx-window-token-5.0.0.tgz#ca63a25038c9fdd73159857276ff67ec7f5b730b" integrity sha512-DhigCrm9QO8R29lqJYzBC9aaTU0KiWgdnt8RNcTN/DvMaS7shfzAqyvUtxSIm/+JR4gW5JKqR/JODU8760nJMw== @@ -9064,45 +6745,6 @@ node-gyp@^7.1.0: tar "^6.0.2" which "^2.0.2" -node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-releases@^1.1.61: - version "1.1.61" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.61.tgz#707b0fca9ce4e11783612ba4a2fcba09047af16e" - integrity sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g== - -node-releases@^1.1.71: - version "1.1.72" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" - integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== - node-releases@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" @@ -9132,11 +6774,6 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= -normalize-url@^4.5.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" @@ -9161,7 +6798,7 @@ npm-normalize-package-bin@^1.0.1: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@8.1.5: +npm-package-arg@8.1.5, npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.2: version "8.1.5" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== @@ -9170,24 +6807,6 @@ npm-package-arg@8.1.5: semver "^7.3.4" validate-npm-package-name "^3.0.0" -npm-package-arg@^8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.0.1.tgz#9d76f8d7667b2373ffda60bb801a27ef71e3e270" - integrity sha512-/h5Fm6a/exByzFSTm7jAyHbgOqErl9qSNJDQF32Si/ZzgwT2TERVxRxn3Jurw1wflgyVVAxnFR4fRHPM7y1ClQ== - dependencies: - hosted-git-info "^3.0.2" - semver "^7.0.0" - validate-npm-package-name "^3.0.0" - -npm-package-arg@^8.0.1, npm-package-arg@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.2.tgz#b868016ae7de5619e729993fbd8d11dc3c52ab62" - integrity sha512-6Eem455JsSMJY6Kpd3EyWE+n5hC+g9bSyHr9K9U2zqZb7+02+hObQ2c0+8iDk/mNF+8r1MhY44WypKJAkySIYA== - dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" - validate-npm-package-name "^3.0.0" - npm-packlist@^2.1.4: version "2.2.2" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" @@ -9238,9 +6857,9 @@ npmlog@^4.1.2: set-blocking "~2.0.0" nth-check@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125" - integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q== + version "2.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== dependencies: boolbase "^1.0.0" @@ -9259,7 +6878,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@4.x, object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -9273,18 +6892,13 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" - integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== - object-is@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.3.tgz#2e3b9e65560137455ee3bd62aec4d90a2ea1cc81" - integrity sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg== + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" @@ -9298,13 +6912,13 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.0, object.assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd" - integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA== +object.assign@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.18.0-next.0" has-symbols "^1.0.1" object-keys "^1.1.1" @@ -9351,14 +6965,6 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.0.tgz#ad95b98f871d9acb0ec8fecc557082cc9986626b" - integrity sha512-PGoBCX/lclIWlpS/R2PQuIR4NJoXh6X5AwVzE7WXnWRGvHg7+4TBCgsujUgiPpm0K1y4qvQeWnCWVTpTKZBtvA== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - open@8.2.1: version "8.2.1" resolved "https://registry.yarnpkg.com/open/-/open-8.2.1.tgz#82de42da0ccbf429bc12d099dad2e0975e14e8af" @@ -9383,20 +6989,6 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" -ora@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.3.0.tgz#fb832899d3a1372fe71c8b2c534bbfe74961bb6f" - integrity sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g== - dependencies: - bl "^4.0.3" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - log-symbols "^4.0.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - ora@5.4.1, ora@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" @@ -9419,11 +7011,6 @@ original@^1.0.0: dependencies: url-parse "^1.4.3" -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -9446,14 +7033,7 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.0.2.tgz#1664e010af3cadc681baafd3e2a437be7b0fb5fe" - integrity sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg== - dependencies: - p-try "^2.0.0" - -p-limit@^3.1.0: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -9523,20 +7103,11 @@ pacote@11.3.5: ssri "^8.0.1" tar "^6.1.0" -pako@^1.0.3, pako@~1.0.2, pako@~1.0.5: +pako@^1.0.3, pako@~1.0.2: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -9544,17 +7115,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -9631,11 +7191,6 @@ patch-package@^6.4.7: slash "^2.0.0" tmp "^0.0.33" -path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -9667,9 +7222,9 @@ path-key@^2.0.0, path-key@^2.0.1: integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-to-regexp@0.1.7: version "0.1.7" @@ -9681,17 +7236,6 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pbkdf2@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" - integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -9707,12 +7251,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: version "2.3.0" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== @@ -9764,17 +7303,10 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" -pngjs@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" - integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== - -pnp-webpack-plugin@1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" - integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg== - dependencies: - ts-pnp "^1.1.6" +pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== polygon-clipping@0.15.3: version "0.15.3" @@ -9860,15 +7392,6 @@ postcss-color-rebeccapurple@^4.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-colormin@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.1.1.tgz#834d262f6021f832d9085e355f08ade288a92a1d" - integrity sha512-SyTmqKKN6PyYNeeKEC0hqIP5CDuprO1hHurdW1aezDyfofDUOn7y7MaxcolbsW3oazPwFiGiY30XRiW1V4iZpA== - dependencies: - browserslist "^4.16.0" - colord "^2.0.0" - postcss-value-parser "^4.1.0" - postcss-colormin@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.1.tgz#6e444a806fd3c578827dbad022762df19334414d" @@ -9879,13 +7402,6 @@ postcss-colormin@^5.2.1: colord "^2.9.1" postcss-value-parser "^4.1.0" -postcss-convert-values@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz#4ec19d6016534e30e3102fdf414e753398645232" - integrity sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg== - dependencies: - postcss-value-parser "^4.1.0" - postcss-convert-values@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059" @@ -9996,15 +7512,6 @@ postcss-image-set-function@^3.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-import@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.0.0.tgz#3ed1dadac5a16650bde3f4cdea6633b9c3c78296" - integrity sha512-gFDDzXhqr9ELmnLHgCC3TbGfA6Dm/YMb/UN8/f7Uuq4fL7VTk2vOIj6hwINEwbokEmp123bLD7a5m+E+KIetRg== - dependencies: - postcss-value-parser "^4.0.0" - read-cache "^1.0.0" - resolve "^1.1.7" - postcss-import@14.0.2: version "14.0.2" resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.0.2.tgz#60eff77e6be92e7b67fe469ec797d9424cae1aa1" @@ -10030,17 +7537,6 @@ postcss-lab-function@^2.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-loader@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.2.0.tgz#f6993ea3e0f46600fb3ee49bbd010448123a7db4" - integrity sha512-mqgScxHqbiz1yxbnNcPdKYo/6aVt+XExURmEbQlviFVWogDbM4AJ0A/B+ZBpYsJrTRxKw7HyRazg9x0Q9SWwLA== - dependencies: - cosmiconfig "^7.0.0" - klona "^2.0.4" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - semver "^7.3.4" - postcss-loader@6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.1.1.tgz#58dd0a3accd9bc87cc52eff75244db578d11301a" @@ -10064,33 +7560,13 @@ postcss-media-minmax@^4.0.0: dependencies: postcss "^7.0.2" -postcss-merge-longhand@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz#277ada51d9a7958e8ef8cf263103c9384b322a41" - integrity sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw== - dependencies: - css-color-names "^1.0.1" - postcss-value-parser "^4.1.0" - stylehacks "^5.0.1" - postcss-merge-longhand@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" - integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== - dependencies: - postcss-value-parser "^4.1.0" - stylehacks "^5.0.1" - -postcss-merge-rules@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.1.tgz#4ff61c5089d86845184a0f149e88d687028bef7e" - integrity sha512-UR6R5Ph0c96QB9TMBH3ml8/kvPCThPHepdhRqAbvMRDRHQACPC8iM5NpfIC03+VRMZTGXy4L/BvFzcDFCgb+fA== - dependencies: - browserslist "^4.16.0" - caniuse-api "^3.0.0" - cssnano-utils "^2.0.1" - postcss-selector-parser "^6.0.5" - vendors "^1.0.3" + integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== + dependencies: + postcss-value-parser "^4.1.0" + stylehacks "^5.0.1" postcss-merge-rules@^5.0.3: version "5.0.3" @@ -10109,15 +7585,6 @@ postcss-minify-font-values@^5.0.1: dependencies: postcss-value-parser "^4.1.0" -postcss-minify-gradients@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.1.tgz#2dc79fd1a1afcb72a9e727bc549ce860f93565d2" - integrity sha512-odOwBFAIn2wIv+XYRpoN2hUV3pPQlgbJ10XeXPq8UY2N+9ZG42xu45lTn/g9zZ+d70NKSQD6EOi6UiCMu3FN7g== - dependencies: - cssnano-utils "^2.0.1" - is-color-stop "^1.1.0" - postcss-value-parser "^4.1.0" - postcss-minify-gradients@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz#f970a11cc71e08e9095e78ec3a6b34b91c19550e" @@ -10127,17 +7594,6 @@ postcss-minify-gradients@^5.0.3: cssnano-utils "^2.0.1" postcss-value-parser "^4.1.0" -postcss-minify-params@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz#371153ba164b9d8562842fdcd929c98abd9e5b6c" - integrity sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw== - dependencies: - alphanum-sort "^1.0.2" - browserslist "^4.16.0" - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - uniqs "^2.0.0" - postcss-minify-params@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.2.tgz#1b644da903473fbbb18fbe07b8e239883684b85c" @@ -10242,15 +7698,6 @@ postcss-normalize-unicode@^5.0.1: browserslist "^4.16.0" postcss-value-parser "^4.1.0" -postcss-normalize-url@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.1.tgz#ffa9fe545935d8b57becbbb7934dd5e245513183" - integrity sha512-hkbG0j58Z1M830/CJ73VsP7gvlG1yF+4y7Fd1w4tD2c7CaA2Psll+pQ6eQhth9y9EaqZSLzamff/D0MZBMbYSg== - dependencies: - is-absolute-url "^3.0.3" - normalize-url "^4.5.0" - postcss-value-parser "^4.1.0" - postcss-normalize-url@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.3.tgz#42eca6ede57fe69075fab0f88ac8e48916ef931c" @@ -10267,14 +7714,6 @@ postcss-normalize-whitespace@^5.0.1: dependencies: postcss-value-parser "^4.1.0" -postcss-ordered-values@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.1.tgz#79ef6e2bd267ccad3fc0c4f4a586dfd01c131f64" - integrity sha512-6mkCF5BQ25HvEcDfrMHCLLFHlraBSlOXFnQMHYhSpDO/5jSR1k8LdEXOkv+7+uzW6o6tBYea1Km0wQSRkPJkwA== - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - postcss-ordered-values@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044" @@ -10356,14 +7795,6 @@ postcss-pseudo-class-any-link@^6.0.0: postcss "^7.0.2" postcss-selector-parser "^5.0.0-rc.3" -postcss-reduce-initial@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz#9d6369865b0f6f6f6b165a0ef5dc1a4856c7e946" - integrity sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw== - dependencies: - browserslist "^4.16.0" - caniuse-api "^3.0.0" - postcss-reduce-initial@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048" @@ -10412,17 +7843,7 @@ postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-selector-parser@^6.0.2: - version "6.0.4" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3" - integrity sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw== - dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - util-deprecate "^1.0.2" - -postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: version "6.0.6" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== @@ -10430,14 +7851,6 @@ postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-svgo@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.1.tgz#6ed5e01e164e59204978994d844c653a331a8100" - integrity sha512-cD7DFo6tF9i5eWvwtI4irKOHCpmASFS0xvZ5EQIgEdA1AWfM/XiHHY/iss0gcKHhkqwgYmuo2M0KhJLd5Us6mg== - dependencies: - postcss-value-parser "^4.1.0" - svgo "^2.3.0" - postcss-svgo@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30" @@ -10446,15 +7859,6 @@ postcss-svgo@^5.0.3: postcss-value-parser "^4.1.0" svgo "^2.7.0" -postcss-unique-selectors@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz#3be5c1d7363352eff838bd62b0b07a0abad43bfc" - integrity sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w== - dependencies: - alphanum-sort "^1.0.2" - postcss-selector-parser "^6.0.5" - uniqs "^2.0.0" - postcss-unique-selectors@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1" @@ -10464,9 +7868,9 @@ postcss-unique-selectors@^5.0.2: postcss-selector-parser "^6.0.5" postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: version "2.0.1" @@ -10477,15 +7881,6 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@8.2.14: - version "8.2.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.14.tgz#dcf313eb8247b3ce8078d048c0e8262ca565ad2b" - integrity sha512-+jD0ZijcvyCqPQo/m/CW0UcARpdFylq04of+Q7RKX6f/Tu+dvpUI/9Sp81+i6/vJThnOBX09Quw0ZLOVwpzX3w== - dependencies: - colorette "^1.2.2" - nanoid "^3.1.22" - source-map "^0.6.1" - postcss@8.3.6: version "8.3.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" @@ -10495,7 +7890,7 @@ postcss@8.3.6: nanoid "^3.1.23" source-map-js "^0.6.2" -postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: +postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.5, postcss@^7.0.6: version "7.0.39" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== @@ -10503,24 +7898,6 @@ postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0. picocolors "^0.2.1" source-map "^0.6.1" -postcss@^7.0.35: - version "7.0.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" - integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^8.1.4: - version "8.3.0" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.0.tgz#b1a713f6172ca427e3f05ef1303de8b65683325f" - integrity sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ== - dependencies: - colorette "^1.2.2" - nanoid "^3.1.23" - source-map-js "^0.6.2" - postcss@^8.2.15, postcss@^8.3.5, postcss@^8.3.7: version "8.4.4" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.4.tgz#d53d4ec6a75fd62557a66bb41978bf47ff0c2869" @@ -10535,33 +7912,26 @@ postinstall-prepare@^2.0.0: resolved "https://registry.yarnpkg.com/postinstall-prepare/-/postinstall-prepare-2.0.0.tgz#2a6867c1a13a05502aa115d0495efbbd778769cb" integrity sha512-lLFwEKdnGLAaRAm8OpXP6HwrXRW+b8Hh9vRhVHZKmCdobd+D21YM38BCDsi3zrePLSe8Tt0H/mbYkh7/ySQQMg== -prettier@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.2.tgz#3050700dae2e4c8b67c4c3f666cdb8af405e1ce5" - integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg== +prettier@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893" + integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg== pretty-bytes@^5.3.0: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== -prismjs@^1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33" - integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA== - optionalDependencies: - clipboard "^2.0.0" +prismjs@^1.23.0, prismjs@^1.25.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" + integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -10575,7 +7945,7 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" -prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -10611,11 +7981,11 @@ protractor@~7.0.0: yargs "^15.3.1" proxy-addr@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: - forwarded "~0.1.2" + forwarded "0.2.0" ipaddr.js "1.9.1" prr@~1.0.1: @@ -10633,26 +8003,6 @@ psl@^1.1.28: resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -10661,25 +8011,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -10700,18 +8036,15 @@ qjobs@^1.2.0: resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== -qrcode@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83" - integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q== +qrcode@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b" + integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ== dependencies: - buffer "^5.4.3" - buffer-alloc "^1.2.0" - buffer-from "^1.1.1" dijkstrajs "^1.0.1" - isarray "^2.0.1" - pngjs "^3.3.0" - yargs "^13.2.4" + encode-utf8 "^1.0.3" + pngjs "^5.0.0" + yargs "^15.3.1" qs@6.7.0: version "6.7.0" @@ -10723,11 +8056,6 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -10738,33 +8066,23 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + quickselect@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw== -raf@^3.4.0, raf@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" - integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== - dependencies: - performance-now "^2.1.0" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: +randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -10787,7 +8105,7 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-loader@4.0.2: +raw-loader@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6" integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA== @@ -10803,126 +8121,115 @@ rbush@^3.0.1: quickselect "^2.0.0" rc-align@^4.0.0: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.8.tgz#276c3f5dfadf0de4bb95392cb81568c9e947a668" - integrity sha512-2sRUkmB8z4UEXzaS+lDHzXMoR8HrtKH9nn2yHlHVNyUTnaucjMFbdEoCk+hO1g7cpIgW0MphG8i0EH2scSesfw== + version "4.0.11" + resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.11.tgz#8198c62db266bc1b8ef05e56c13275bf72628a5e" + integrity sha512-n9mQfIYQbbNTbefyQnRHZPWuTEwG1rY4a9yKlIWHSTbgwI+XUMGRYd0uJ5pE2UbrNX0WvnMBA1zJ3Lrecpra/A== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" dom-align "^1.7.0" + lodash "^4.17.21" rc-util "^5.3.0" resize-observer-polyfill "^1.5.1" -rc-animate@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-3.1.1.tgz#defdd863f56816c222534e4dc68feddecd081386" - integrity sha512-8wg2Zg3EETy0k/9kYuis30NJNQg1D6/WSQwnCiz6SvyxQXNet/rVraRz3bPngwY6rcU2nlRvoShiYOorXyF7Sg== +rc-motion@^2.0.0, rc-motion@^2.0.1: + version "2.4.4" + resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.4.4.tgz#e995d5fa24fc93065c24f714857cf2677d655bb0" + integrity sha512-ms7n1+/TZQBS0Ydd2Q5P4+wJTSOrhIrwNxLXCZpR7Fa3/oac7Yi803HDALc2hLAKaCTQtw9LmQeB58zcwOsqlQ== dependencies: - "@ant-design/css-animation" "^1.7.2" - classnames "^2.2.6" - raf "^3.4.0" - rc-util "^4.15.3" + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-util "^5.2.1" -rc-motion@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-1.1.2.tgz#07212f1b96c715b8245ec121339146c4a9b0968c" - integrity sha512-YC/E7SSWKBFakYg4PENhSRWD4ZLDqkI7FKmutJcrMewZ91/ZIWfoZSDvPaBdKO0hsFrrzWepFhXQIq0FNnCMWA== +rc-overflow@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.2.2.tgz#95b0222016c0cdbdc0db85f569c262e7706a5f22" + integrity sha512-X5kj9LDU1ue5wHkqvCprJWLKC+ZLs3p4He/oxjZ1Q4NKaqKBaYf5OdSzRSgh3WH8kSdrfU8LjvlbWnHgJOEkNQ== dependencies: "@babel/runtime" "^7.11.1" classnames "^2.2.1" - raf "^3.4.1" - rc-util "^5.0.6" + rc-resize-observer "^1.0.0" + rc-util "^5.5.1" -rc-select@~10.5.1: - version "10.5.1" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-10.5.1.tgz#4d4c5d4f8d2fd3b7e3dccf74e4c43142b2979247" - integrity sha512-fZraoNNhjUmDJccfk6VYgrgHBWFmHWh/NJZh2Xttcm/usOolYI1RjO9ikP4QGhzlJBFtnTLH2pE2nchjn3TCXA== +rc-resize-observer@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.1.1.tgz#ef666e38065f550730176404bae2ce8ca5fb1ac4" + integrity sha512-5A3B9ha297ItltzXl812WFE36SyRDTNclfrXE3FL1pEwXkBh7iSEzxjzfwsPeMcF9ahy3ZoxLgLuRksXBGGD6A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.15.0" + resize-observer-polyfill "^1.5.1" + +rc-select@~13.2.0: + version "13.2.1" + resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-13.2.1.tgz#d69675f8bc72622a8f3bc024fa21bfee8d56257d" + integrity sha512-L2cJFAjVEeDiNVa/dlOVKE79OUb0J7sUBvWN3Viav3XHcjvv9Ovn4D8J9QhBSlDXeGuczZ81CZI3BbdHD25+Gg== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" - rc-animate "^3.0.0" - rc-trigger "^4.3.0" - rc-util "^5.0.1" - rc-virtual-list "^1.1.2" - warning "^4.0.3" + rc-motion "^2.0.1" + rc-overflow "^1.0.0" + rc-trigger "^5.0.4" + rc-util "^5.9.8" + rc-virtual-list "^3.2.0" -rc-trigger@^4.3.0: - version "4.4.3" - resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-4.4.3.tgz#ed449cd6cce446555bc57f4394229c5c7154f4b0" - integrity sha512-yq/WyuiPwxd2q6jy+VPyy0GUCRFJ2eFqAaCwPE27AOftXeIupOcJ/2t1wakSq63cfk7qtzev5DKHUAjb8LOJCw== +rc-trigger@^5.0.4: + version "5.2.10" + resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-5.2.10.tgz#8a0057a940b1b9027eaa33beec8a6ecd85cce2b1" + integrity sha512-FkUf4H9BOFDaIwu42fvRycXMAvkttph9AlbCZXssZDVzz2L+QZ0ERvfB/4nX3ZFPh1Zd+uVGr1DEDeXxq4J1TA== dependencies: "@babel/runtime" "^7.11.2" classnames "^2.2.6" - raf "^3.4.1" rc-align "^4.0.0" - rc-motion "^1.0.0" - rc-util "^5.0.1" - -rc-util@^4.15.3: - version "4.21.1" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.21.1.tgz#88602d0c3185020aa1053d9a1e70eac161becb05" - integrity sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg== - dependencies: - add-dom-event-listener "^1.1.0" - prop-types "^15.5.10" - react-is "^16.12.0" - react-lifecycles-compat "^3.0.4" - shallowequal "^1.1.0" - -rc-util@^5.0.0, rc-util@^5.0.1, rc-util@^5.3.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.4.0.tgz#688eaeecfdae9dae2bfdf10bedbe884591dba004" - integrity sha512-kXDn1JyLJTAWLBFt+fjkTcUtXhxKkipQCobQmxIEVrX62iXgo24z8YKoWehWfMxPZFPE+RXqrmEu9j5kHz/Lrg== - dependencies: - react-is "^16.12.0" - shallowequal "^1.1.0" + rc-motion "^2.0.0" + rc-util "^5.5.0" -rc-util@^5.0.6: - version "5.7.0" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.7.0.tgz#776b14cf5bbfc24f419fd40c42ffadddda0718fc" - integrity sha512-0hh5XkJ+vBDeMJsHElqT1ijMx+gC3gpClwQ10h/5hccrrgrMx8VUem183KLlH1YrWCfMMPmDXWWNnwsn+p6URw== +rc-util@^5.0.7, rc-util@^5.15.0, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.5.0, rc-util@^5.5.1, rc-util@^5.9.8: + version "5.16.1" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.16.1.tgz#374db7cb735512f05165ddc3d6b2c61c21b8b4e3" + integrity sha512-kSCyytvdb3aRxQacS/71ta6c+kBWvM1v8/2h9d/HaNWauc3qB8pLnF20PJ8NajkNN8gb+rR1l0eWO+D4Pz+LLQ== dependencies: "@babel/runtime" "^7.12.5" react-is "^16.12.0" shallowequal "^1.1.0" -rc-virtual-list@^1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-1.1.6.tgz#b255baf9aacde149a8893324e6307214094f4c0a" - integrity sha512-u3+izqWL8p8bQy8nYH48qWpiGyxR/ye8D2k0zJlXmfYeL55/xh83YrzHqiDzO78uj0Ewag3nXDA0JTVrYO7ygQ== +rc-virtual-list@^3.2.0: + version "3.4.2" + resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.4.2.tgz#1078327aa7230b5e456d679ed2ce99f3c036ebd1" + integrity sha512-OyVrrPvvFcHvV0ssz5EDZ+7Rf5qLat/+mmujjchNw5FfbJWNDwkpQ99EcVE6+FtNRmX9wFa1LGNpZLUTvp/4GQ== dependencies: classnames "^2.2.6" - raf "^3.4.1" - rc-util "^5.0.0" + rc-resize-observer "^1.0.0" + rc-util "^5.0.7" -react-ace@^9.1.4: - version "9.1.4" - resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-9.1.4.tgz#7c45c361aa5fe1efa3313fa876bce30aa64a244f" - integrity sha512-4DBWvElbVR3WhsA2HhQ524K9Yoa/J/sjuBV9NUZ+yar3Q4BGJRTnhY6pM0INffH1IkBZHKIOyz34XHjc7RNTpw== +react-ace@^9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-9.5.0.tgz#b6c32b70d404dd821a7e01accc2d76da667ff1f7" + integrity sha512-4l5FgwGh6K7A0yWVMQlPIXDItM4Q9zzXRqOae8KkCl6MkOob7sC1CzHxZdOGvV+QioKWbX2p5HcdOVUv6cAdSg== dependencies: - ace-builds "^1.4.6" - diff-match-patch "^1.0.4" + ace-builds "^1.4.13" + diff-match-patch "^1.0.5" lodash.get "^4.4.2" lodash.isequal "^4.5.0" prop-types "^15.7.2" -react-dom@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" - integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" + scheduler "^0.20.2" -react-dropzone@^11.2.0: - version "11.2.0" - resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-11.2.0.tgz#4e54fa3479e6b6bb93f67914e4a27f1260807fdb" - integrity sha512-S/qaXQHCCg7MVlcrhqd05MLC6DupITLUB0CFn3iCLs6OTjzxdGDF1WTktTe5Jyq8jZdxYfMHNUZOHL0mg+K0Dw== +react-dropzone@^11.4.2: + version "11.4.2" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-11.4.2.tgz#1eb99e9def4cc7520f4f58e85c853ce52c483d56" + integrity sha512-ocYzYn7Qgp0tFc1gQtUTOaHHSzVTwhWHxxY+r7cj2jJTPfMTZB5GWSJHdIVoxsl+EQENpjJ/6Zvcw0BqKZQ+Eg== dependencies: - attr-accept "^2.0.0" - file-selector "^0.1.12" + attr-accept "^2.2.1" + file-selector "^0.2.2" prop-types "^15.7.2" react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1: @@ -10935,29 +8242,23 @@ react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-lifecycles-compat@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - react-transition-group@^4.0.0, react-transition-group@^4.4.0: - version "4.4.1" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" - integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw== + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" + integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== dependencies: "@babel/runtime" "^7.5.5" dom-helpers "^5.0.1" loose-envify "^1.4.0" prop-types "^15.6.2" -react@~16.14.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" - integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== +react@~17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" reactcss@^1.2.3: version "1.2.3" @@ -10974,14 +8275,14 @@ read-cache@^1.0.0: pify "^2.3.0" read-package-json-fast@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz#2dcb24d9e8dd50fb322042c8c35a954e6cc7ac9e" - integrity sha512-5fyFUyO9B799foVk4n6ylcoAktG/FbE3jwRKxvwaeSrIunaoMc0u81dzXxjeAFKOce7O5KncdfwpGvvs6r5PsQ== + version "2.0.3" + resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" + integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== dependencies: json-parse-even-better-errors "^2.3.0" npm-normalize-package-bin "^1.0.1" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -10994,7 +8295,7 @@ read-package-json-fast@^2.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.6, readable-stream@^3.4.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -11012,20 +8313,6 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" - integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== - dependencies: - picomatch "^2.2.1" - -readdirp@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" - integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== - dependencies: - picomatch "^2.2.1" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -11038,24 +8325,19 @@ reflect-metadata@^0.1.2: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" - integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== + regenerate "^1.4.2" -regenerator-runtime@0.13.7, regenerator-runtime@^0.13.4: - version "0.13.7" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" - integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@0.13.9: +regenerator-runtime@0.13.9, regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== @@ -11081,34 +8363,34 @@ regex-parser@^2.2.11: integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== regexp.prototype.flags@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" - integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" -regexpu-core@^4.7.0, regexpu-core@^4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" - integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== +regexpu-core@^4.7.1: + version "4.8.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" -regjsgen@^0.5.1: +regjsgen@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== -regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== dependencies: jsesc "~0.5.0" @@ -11118,9 +8400,9 @@ remove-trailing-separator@^1.0.1: integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== repeat-string@^1.6.1: version "1.6.1" @@ -11211,7 +8493,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.20.0, resolve@^1.14.2: +resolve@1.20.0, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.3.2: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -11219,13 +8501,6 @@ resolve@1.20.0, resolve@^1.14.2: is-core-module "^2.2.0" path-parse "^1.0.6" -resolve@^1.1.7, resolve@^1.3.2: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -11250,19 +8525,9 @@ reusify@^1.0.4: integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rfdc@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2" - integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug== - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== rifm@^0.7.0: version "0.7.0" @@ -11271,13 +8536,6 @@ rifm@^0.7.0: dependencies: "@babel/runtime" "^7.3.1" -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -11285,20 +8543,12 @@ rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3: dependencies: glob "^7.1.3" -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rollup@2.38.4: - version "2.38.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.38.4.tgz#1b84ea8728c73b1a00a6a6e9c630ec8c3fe48cea" - integrity sha512-B0LcJhjiwKkTl79aGVF/u5KdzsH8IylVfV56Ut6c9ouWLJcUK17T83aZBetNYSnZtXf2OHD4+2PbmRW+Fp5ulg== - optionalDependencies: - fsevents "~2.3.1" + glob "^7.1.3" run-async@^2.4.0: version "2.4.1" @@ -11306,25 +8556,13 @@ run-async@^2.4.0: integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== run-parallel@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" - integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rxjs@6.6.3, rxjs@^6.5.3, rxjs@^6.6.0: - version "6.6.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" - integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: - tslib "^1.9.0" + queue-microtask "^1.2.2" -rxjs@6.6.7, rxjs@~6.6.7: +rxjs@6.6.7, rxjs@^6.5.3, rxjs@~6.6.7: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== @@ -11343,7 +8581,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -11360,17 +8598,6 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass-loader@10.1.1: - version "10.1.1" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.1.1.tgz#4ddd5a3d7638e7949065dd6e9c7c04037f7e663d" - integrity sha512-W6gVDXAd5hR/WHsPicvZdjAWHBcEJ44UahgxcIE196fW2ong0ZHMPO1kZuI5q0VlvMQZh32gpv69PLWQm70qrw== - dependencies: - klona "^2.0.4" - loader-utils "^2.0.0" - neo-async "^2.6.2" - schema-utils "^3.0.0" - semver "^7.3.2" - sass-loader@12.1.0: version "12.1.0" resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.1.0.tgz#b73324622231009da6fba61ab76013256380d201" @@ -11379,13 +8606,6 @@ sass-loader@12.1.0: klona "^2.0.4" neo-async "^2.6.2" -sass@1.32.6: - version "1.32.6" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.6.tgz#e3646c8325cd97ff75a8a15226007f3ccd221393" - integrity sha512-1bcDHDcSqeFtMr0JXI3xc/CXX6c4p0wHHivJdru8W7waM7a1WjKMm4m/Z5sY7CbVw4Whi2Chpcw6DFfSWwGLzQ== - dependencies: - chokidar ">=2.0.0 <4.0.0" - sass@1.36.0: version "1.36.0" resolved "https://registry.yarnpkg.com/sass/-/sass-1.36.0.tgz#5912ef9d5d16714171ba11cb17edb274c4bbc07e" @@ -11405,10 +8625,10 @@ sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -11438,16 +8658,7 @@ schema-utils@^2.6.5, schema-utils@^2.7.0: ajv "^6.12.4" ajv-keywords "^3.5.2" -schema-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef" - integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA== - dependencies: - "@types/json-schema" "^7.0.6" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^3.1.0, schema-utils@^3.1.1: +schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== @@ -11456,21 +8667,26 @@ schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" -screenfull@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.1.0.tgz#85c13c70f4ead4c1b8a935c70010dfdcd2c0e5c8" - integrity sha512-dYaNuOdzr+kc6J6CFcBrzkLCfyGcMg+gWkJ8us93IQ7y1cevhQAugFsaCdMHb6lw8KV3xPzSxzH7zM1dQap9mA== +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +screenfull@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-6.0.0.tgz#6f7f37bfe19c5ee50931ac438c1fe380d5b5ff44" + integrity sha512-LGY0nhNQkC4FX4DT4pZdJ5cZH5EOz9Gfh9KcVMl779pS677k4IV1Wv7sY/CwC9VKFT21fYgCh7zkTVVefi5XKA== select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -select@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" - integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= - selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: version "3.6.0" resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" @@ -11500,21 +8716,14 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== - dependencies: - lru-cache "^6.0.0" - -semver@7.3.5, semver@^7.3.4, semver@^7.3.5: +semver@7.3.5, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" -semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -11524,11 +8733,6 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.0.0, semver@^7.1.1, semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== - send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -11548,20 +8752,6 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - -serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== - dependencies: - randombytes "^2.1.0" - serialize-javascript@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" @@ -11612,11 +8802,6 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -11627,14 +8812,6 @@ setprototypeof@1.1.1: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -11665,9 +8842,9 @@ sigmund@^1.0.1: integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== slash@^2.0.0: version "2.0.0" @@ -11680,9 +8857,9 @@ slash@^3.0.0: integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== snapdragon-node@^2.0.1: version "2.1.1" @@ -11714,12 +8891,12 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -socket.io-adapter@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.1.0.tgz#edc5dc36602f2985918d631c1399215e97a1b527" - integrity sha512-+vDov/aTsLjViYTwS9fPy5pEtTkrbEKsw2M+oVSoFGw6OD1IpvlV1VPhUzNbofCQ8oyMbdYJqDtGdmHQK6TdPg== +socket.io-adapter@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz#4d6111e4d42e9f7646e365b4f578269821f13486" + integrity sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ== -socket.io-parser@~4.0.3: +socket.io-parser@~4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.4.tgz#9ea21b0d61508d18196ef04a2c6b9ab630f4c2b0" integrity sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g== @@ -11728,40 +8905,37 @@ socket.io-parser@~4.0.3: component-emitter "~1.3.0" debug "~4.3.1" -socket.io@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-3.1.2.tgz#06e27caa1c4fc9617547acfbb5da9bc1747da39a" - integrity sha512-JubKZnTQ4Z8G4IZWtaAZSiRP3I/inpy8c/Bsx2jrwGrTbKeVU5xd6qkKMHpChYeM3dWZSO0QACiGK+obhBNwYw== +socket.io@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.4.0.tgz#8140a0db2c22235f88a6dceb867e4d5c9bd70507" + integrity sha512-bnpJxswR9ov0Bw6ilhCvO38/1WPtE3eA2dtxi2Iq4/sFebiDJQzgKNYA7AuVVdGW09nrESXd90NbZqtDd9dzRQ== dependencies: - "@types/cookie" "^0.4.0" - "@types/cors" "^2.8.8" - "@types/node" ">=10.0.0" accepts "~1.3.4" base64id "~2.0.0" - debug "~4.3.1" - engine.io "~4.1.0" - socket.io-adapter "~2.1.0" - socket.io-parser "~4.0.3" + debug "~4.3.2" + engine.io "~6.1.0" + socket.io-adapter "~2.3.3" + socket.io-parser "~4.0.4" sockjs-client@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.1.tgz#256908f6d5adfb94dabbdbd02c66362cca0f9ea6" - integrity sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ== + version "1.5.2" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.2.tgz#4bc48c2da9ce4769f19dc723396b50f5c12330a3" + integrity sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ== dependencies: debug "^3.2.6" eventsource "^1.0.7" faye-websocket "^0.11.3" inherits "^2.0.4" json3 "^3.3.3" - url-parse "^1.5.1" + url-parse "^1.5.3" sockjs@^0.3.21: - version "0.3.21" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417" - integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw== + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== dependencies: faye-websocket "^0.11.3" - uuid "^3.4.0" + uuid "^8.3.2" websocket-driver "^0.7.4" socks-proxy-agent@^6.0.0: @@ -11781,7 +8955,7 @@ socks@^2.6.1: ip "^1.1.5" smart-buffer "^4.1.0" -source-list-map@^2.0.0, source-list-map@^2.0.1: +source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== @@ -11796,18 +8970,6 @@ source-map-js@^1.0.1: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== -source-map-loader@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-1.1.3.tgz#7dbc2fe7ea09d3e43c51fd9fc478b7f016c1f820" - integrity sha512-6YHeF+XzDOrT/ycFJNI53cgEsp/tHTMl37hi7uVyqFAlTXW109JazaQCkbc+jjoL2637qkH1amLi+JzrIpt5lA== - dependencies: - abab "^2.0.5" - iconv-lite "^0.6.2" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - source-map "^0.6.1" - whatwg-mimetype "^2.3.0" - source-map-loader@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.0.tgz#f2a04ee2808ad01c774dea6b7d2639839f3b3049" @@ -11828,15 +8990,7 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: source-map-url "^0.4.0" urix "^0.1.0" -source-map-resolve@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" - integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - -source-map-support@0.5.19, source-map-support@^0.5.17, source-map-support@^0.5.5, source-map-support@~0.5.12, source-map-support@~0.5.19: +source-map-support@0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -11844,25 +8998,25 @@ source-map-support@0.5.19, source-map-support@^0.5.17, source-map-support@^0.5.5 buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@~0.4.0: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - -source-map-support@~0.5.20: +source-map-support@^0.5.5, source-map-support@~0.5.19, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.4.0: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" @@ -11907,13 +9061,6 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" -speed-measure-webpack-plugin@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.4.2.tgz#1608e62d3bdb45f01810010e1b5bfedefedfa58f" - integrity sha512-AtVzD0bnIy2/B0fWqJpJgmhcrfWFhBlduzSo0uwplr/QvB33ZNZj2NEth3NONgdnZJqicK0W0mSxnLSbsVCDbw== - dependencies: - chalk "^4.1.0" - splaytree@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/splaytree/-/splaytree-3.1.0.tgz#17d4a0108a6da3627579690b7b847241e18ddec8" @@ -11956,21 +9103,7 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -ssri@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" - integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== - dependencies: - figgy-pudding "^3.5.1" - -ssri@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.0.tgz#79ca74e21f8ceaeddfcb4b90143c458b8d988808" - integrity sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA== - dependencies: - minipass "^3.1.1" - -ssri@^8.0.1: +ssri@^8.0.0, ssri@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== @@ -11995,38 +9128,6 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - streamroller@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53" @@ -12045,13 +9146,14 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" @@ -12062,32 +9164,7 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.trimend@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" - integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string.prototype.trimstart@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" - integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string_decoder@^1.0.0, string_decoder@^1.1.1: +string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -12108,13 +9185,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -12122,12 +9192,12 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" @@ -12139,14 +9209,6 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= -style-loader@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" - integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - style-loader@3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.2.1.tgz#63cb920ec145c8669e9a50e92961452a1ef5dcde" @@ -12160,17 +9222,6 @@ stylehacks@^5.0.1: browserslist "^4.16.0" postcss-selector-parser "^6.0.4" -stylus-loader@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-4.3.3.tgz#381bb6341272ac50bcdfd0b877707eac99b6b757" - integrity sha512-PpWB5PnCXUzW4WMYhCvNzAHJBjIBPMXwsdfkkKuA9W7k8OQFMl/19/AQvaWsxz2IptxUlCseyJ6TY/eEKJ4+UQ== - dependencies: - fast-glob "^3.2.4" - klona "^2.0.4" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - schema-utils "^3.0.0" - stylus-loader@6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-6.1.0.tgz#7a3a719a27cb2b9617896d6da28fda94c3ed9762" @@ -12213,7 +9264,7 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -12227,19 +9278,6 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -svgo@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.3.0.tgz#6b3af81d0cbd1e19c83f5f63cec2cb98c70b5373" - integrity sha512-fz4IKjNO6HDPgIQxu4IxwtubtbSfGEAJUq/IXyTPIkGhWck/faiiwfkvsB8LnBkKLvSoyNNIY6d13lZprJMc9Q== - dependencies: - "@trysound/sax" "0.1.1" - chalk "^4.1.0" - commander "^7.1.0" - css-select "^3.1.2" - css-tree "^1.1.2" - csso "^4.2.0" - stable "^0.1.8" - svgo@^2.7.0: version "2.8.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" @@ -12253,52 +9291,30 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" -symbol-observable@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== - symbol-observable@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== -systemjs@0.21.5: - version "0.21.5" - resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-0.21.5.tgz#2fcef4edfe744003da4787f3f3d45d73f94462d2" - integrity sha512-GWzZhN/x7Fsae2CYkz2GF7OgOS+YDgKulcgd5L1kTogZHMKDrPx5T8zI8I0y5RoU9Dx78Z7j1XMfuFa1thD84A== +systemjs-babel@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/systemjs-babel/-/systemjs-babel-0.3.1.tgz#4b864be909b542fb7a84303f24d0dbdbc35da2e1" + integrity sha512-ggZ+v7RSKmN1OlAd46REpfZJmBTnrBUH1zgHnSalIB0KPepfPXEm1p2auE6v7wCmJl231EyApRxnw6X3SgpQtA== -tapable@^1.0.0, tapable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +systemjs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.11.0.tgz#8df8e74fc05822e6c40170aa409b9ca64833315f" + integrity sha512-7YPIY44j+BoY+E6cGBSw0oCU8SNTTIHKZgftcBdwWkDzs/M86Fdlr21FrzAyph7Zo8r3CFGscyFe4rrBtixrBg== -tapable@^2.1.1: +tapable@^2.1.1, tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tapable@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" - integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== - -tar@^6.0.2: - version "6.0.5" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" - integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -tar@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" - integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA== +tar@^6.0.2, tar@^6.1.0: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -12307,21 +9323,6 @@ tar@^6.1.0: mkdirp "^1.0.3" yallist "^4.0.0" -terser-webpack-plugin@4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a" - integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ== - dependencies: - cacache "^15.0.5" - find-cache-dir "^3.3.1" - jest-worker "^26.5.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - source-map "^0.6.1" - terser "^5.3.4" - webpack-sources "^1.4.3" - terser-webpack-plugin@5.1.4: version "5.1.4" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz#c369cf8a47aa9922bd0d8a94fe3d3da11a7678a1" @@ -12334,21 +9335,6 @@ terser-webpack-plugin@5.1.4: source-map "^0.6.1" terser "^5.7.0" -terser-webpack-plugin@^1.4.3: - version "1.4.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" - integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - terser-webpack-plugin@^5.1.3: version "5.2.5" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz#ce65b9880a0c36872555c4874f45bbdb02ee32c9" @@ -12360,15 +9346,6 @@ terser-webpack-plugin@^5.1.3: source-map "^0.6.1" terser "^5.7.2" -terser@5.5.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" - integrity sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" - terser@5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784" @@ -12378,24 +9355,6 @@ terser@5.7.1: source-map "~0.7.2" source-map-support "~0.5.19" -terser@^4.1.2: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -terser@^5.3.4: - version "5.7.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.0.tgz#a761eeec206bc87b605ab13029876ead938ae693" - integrity sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" - terser@^5.7.0, terser@^5.7.2: version "5.10.0" resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" @@ -12405,19 +9364,18 @@ terser@^5.7.0, terser@^5.7.2: source-map "~0.7.2" source-map-support "~0.5.20" +text-segmentation@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.2.tgz#1f828fa14aa101c114ded1bda35ba7dcc17c9858" + integrity sha512-uTqvLxdBrVnx/CFQOtnf8tfzSXFm+1Qxau7Xi54j4OPTZokuDOX8qncQzrg2G8ZicAMOM8TgzFAYTb+AqNO4Cw== + dependencies: + utrie "^1.0.1" + text-table@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - through@X.X.X, through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -12428,23 +9386,11 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== -timers-browserify@^2.0.4: - version "2.0.11" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" - integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== - dependencies: - setimmediate "^1.0.4" - timsort@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= -tiny-emitter@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" - integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== - tiny-warning@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" @@ -12462,13 +9408,6 @@ tmp@0.0.30: dependencies: os-tmpdir "~1.0.1" -tmp@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -12476,10 +9415,12 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" to-fast-properties@^2.0.0: version "2.0.0" @@ -12541,61 +9482,53 @@ tree-kill@1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -ts-node@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.0.0.tgz#e7699d2a110cc8c0d3b831715e417688683460b3" - integrity sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg== +ts-node@^10.0.0, ts-node@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" + integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A== dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" arg "^4.1.0" + create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" - source-map-support "^0.5.17" yn "3.1.1" -ts-pnp@^1.1.6: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" - integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== - tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== + version "3.12.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" + integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" minimist "^1.2.0" strip-bom "^3.0.0" -tslib@2.1.0, tslib@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" - integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== - tslib@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== tslib@^1.10.0, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.0.tgz#d624983f3e2c5e0b55307c3dd6c86acd737622c6" - integrity sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw== - -tslib@^2.0.0, tslib@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.2.tgz#462295631185db44b21b1ea3615b63cd1c038242" - integrity sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg== + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0, tslib@^2.3.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tslib@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" - integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== +tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== tslint@~6.1.3: version "6.1.3" @@ -12623,11 +9556,6 @@ tsutils@^2.29.0: dependencies: tslib "^1.8.1" -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -12645,10 +9573,10 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" @@ -12658,53 +9586,43 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - typeface-roboto@^1.1.13: version "1.1.13" resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-1.1.13.tgz#9c4517cb91e311706c74823e857b4bac9a764ae5" integrity sha512-YXvbd3a1QTREoD+FJoEkl0VQNJoEjewR2H11IjVv4bp6ahuIcw0yyw/3udC4vJkHw3T3cUh85FTg8eWef3pSaw== -typescript@4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.5.tgz#123a3b214aaff3be32926f0d8f1f6e704eb89a72" - integrity sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA== - typescript@4.3.5, typescript@~4.3.5: version "4.3.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== -ua-parser-js@^0.7.23: - version "0.7.28" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" - integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== +ua-parser-js@^0.7.30: + version "0.7.31" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" + integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== union-value@^1.0.0: version "1.0.1" @@ -12721,11 +9639,6 @@ uniq@^1.0.1: resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -12764,9 +9677,9 @@ upath@^1.1.1: integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== uri-js@^4.2.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" - integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" @@ -12775,18 +9688,10 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-parse@^1.4.3: - version "1.4.7" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" - integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url-parse@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" - integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== +url-parse@^1.4.3, url-parse@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== dependencies: querystringify "^2.1.1" requires-port "^1.0.0" @@ -12809,31 +9714,24 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@8.3.2: +utrie@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.1.tgz#e155235ebcbddc89ae09261ab6e773ce61401b2f" + integrity sha512-JPaDXF3vzgZxfeEwutdGzlrNoVFL5UvZcbO6Qo9D4GoahrieUPoMU8GCpVpR7MQqcKhmShIh8VlbEN3PLM3EBg== + dependencies: + base64-arraybuffer "^1.0.1" + +uuid@8.3.2, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^3.3.2, uuid@^3.4.0: +uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -12850,11 +9748,6 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -vendors@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" - integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== - verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -12864,41 +9757,11 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - void-elements@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= -warning@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - -watchpack-chokidar2@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0" - integrity sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA== - dependencies: - chokidar "^2.1.8" - -watchpack@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.4.tgz#6e9da53b3c80bb2d6508188f5b200410866cd30b" - integrity sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg== - dependencies: - graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.0" - watchpack@^2.2.0, watchpack@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.0.tgz#a41bca3da6afaff31e92a433f4c856a0c25ea0c4" @@ -12930,9 +9793,9 @@ webdriver-js-extender@2.1.0: selenium-webdriver "^3.0.1" webdriver-manager@^12.1.7: - version "12.1.7" - resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.7.tgz#ed4eaee8f906b33c146e869b55e850553a1b1162" - integrity sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA== + version "12.1.8" + resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.8.tgz#5e70e73eaaf53a0767d5745270addafbc5905fd4" + integrity sha512-qJR36SXG2VwKugPcdwhaqcLQOD7r8P2Xiv9sfNbfZrKBnX243iAkOueX1yAmeNgIKhJ3YAT/F2gq6IiEZzahsg== dependencies: adm-zip "^0.4.9" chalk "^1.1.1" @@ -12946,17 +9809,6 @@ webdriver-manager@^12.1.7: semver "^5.3.0" xml2js "^0.4.17" -webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" - integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== - dependencies: - memory-fs "^0.4.1" - mime "^2.4.4" - mkdirp "^0.5.1" - range-parser "^1.2.1" - webpack-log "^2.0.0" - webpack-dev-middleware@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.0.0.tgz#0abe825275720e0a339978aea5f0b03b140c1584" @@ -12969,6 +9821,17 @@ webpack-dev-middleware@5.0.0: range-parser "^1.2.1" schema-utils "^3.0.0" +webpack-dev-middleware@^3.7.2: + version "3.7.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" + integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + webpack-dev-server@3.11.2: version "3.11.2" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708" @@ -13016,15 +9879,7 @@ webpack-log@^2.0.0: ansi-colors "^3.0.0" uuid "^3.3.2" -webpack-merge@5.7.3, webpack-merge@^5.7.3: - version "5.7.3" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.7.3.tgz#2a0754e1877a25a8bbab3d2475ca70a052708213" - integrity sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA== - dependencies: - clone-deep "^4.0.1" - wildcard "^2.0.0" - -webpack-merge@5.8.0: +webpack-merge@5.8.0, webpack-merge@^5.7.3: version "5.8.0" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== @@ -13032,15 +9887,7 @@ webpack-merge@5.8.0: clone-deep "^4.0.1" wildcard "^2.0.0" -webpack-sources@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac" - integrity sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w== - dependencies: - source-list-map "^2.0.1" - source-map "^0.6.1" - -webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: +webpack-sources@^1.2.0, webpack-sources@^1.3.0: version "1.4.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== @@ -13060,35 +9907,6 @@ webpack-subresource-integrity@1.5.2: dependencies: webpack-sources "^1.3.0" -webpack@4.44.2: - version "4.44.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.44.2.tgz#6bfe2b0af055c8b2d1e90ed2cd9363f841266b72" - integrity sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.3.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" - webpack@5.50.0: version "5.50.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.50.0.tgz#5562d75902a749eb4d75131f5627eac3a3192527" @@ -13163,11 +9981,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -13188,31 +10001,17 @@ which@^2.0.2: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: - string-width "^1.0.2 || 2" + string-width "^1.0.2 || 2 || 3 || 4" wildcard@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - -worker-plugin@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/worker-plugin/-/worker-plugin-5.0.0.tgz#113b5fe1f4a5d6a957cecd29915bedafd70bb537" - integrity sha512-AXMUstURCxDD6yGam2r4E34aJg6kW85IiaeX72hi+I1cxyaMUtrvVY6sbfpGKAj5e7f68Acl62BjQF5aOOx2IQ== - dependencies: - loader-utils "^1.1.0" - wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -13246,16 +10045,16 @@ wrappy@1: integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= ws@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== dependencies: async-limiter "~1.0.0" -ws@~7.4.2: - version "7.4.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1" - integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g== +ws@~8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== xml2js@^0.4.17: version "0.4.23" @@ -13270,15 +10069,10 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== -xtend@^4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== y18n@^5.0.5: version "5.0.8" @@ -13290,11 +10084,6 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -13322,11 +10111,16 @@ yargs-parser@^18.1.2: decamelize "^1.2.0" yargs-parser@^20.2.2: - version "20.2.7" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.0.0: + version "21.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" + integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== -yargs@^13.2.4, yargs@^13.3.2: +yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== @@ -13373,17 +10167,17 @@ yargs@^16.1.1: yargs-parser "^20.2.2" yargs@^17.0.0: - version "17.2.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea" - integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q== + version "17.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.0.tgz#295c4ffd0eef148ef3e48f7a2e0f58d0e4f26b1c" + integrity sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew== dependencies: cliui "^7.0.2" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" - string-width "^4.2.0" + string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^20.2.2" + yargs-parser "^21.0.0" yn@3.1.1: version "3.1.1" From a8dad4c6e0c70e2daa72cab7d393cb6683871b74 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 6 Dec 2021 14:00:21 +0200 Subject: [PATCH 290/303] Improve leaflet-geoman typings --- ui-ngx/src/typings/leaflet-geoman-extend.d.ts | 1493 ++++++++++++++++- ui-ngx/tsconfig.json | 1 - 2 files changed, 1492 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/typings/leaflet-geoman-extend.d.ts b/ui-ngx/src/typings/leaflet-geoman-extend.d.ts index 7b3378aee3..1a936fe780 100644 --- a/ui-ngx/src/typings/leaflet-geoman-extend.d.ts +++ b/ui-ngx/src/typings/leaflet-geoman-extend.d.ts @@ -14,9 +14,1500 @@ /// limitations under the License. /// +/* tslint:disable:adjacent-overload-signatures unified-signatures */ + import * as L from 'leaflet'; -declare module 'leaflet' { +declare module 'leaflet-pm' { + + /** + * Extends built in leaflet Layer Options. + */ + interface LayerOptions { + pmIgnore?: boolean; + snapIgnore?: boolean; + } + + /** + * Extends built in leaflet Map Options. + */ + interface MapOptions { + pmIgnore?: boolean; + } + + /** + * Extends built in leaflet Map. + */ + interface Map { + pm: PM.PMMap; + } + + /** + * Extends built in leaflet Path. + */ + interface Path { + pm: PM.PMLayer; + } + /** + * Extends built in leaflet ImageOverlay. + */ + interface ImageOverlay { + pm: PM.PMLayer; + } + + /** + * Extends built in leaflet LayerGroup. + */ + interface LayerGroup { + pm: PM.PMLayerGroup; + } + + /** + * Extends built in leaflet Polyline. + */ + interface Polyline { + /** Returns true if Line or Polygon has a self intersection. */ + hasSelfIntersection(): boolean; + } + + /** + * Extends @types/leaflet events... + * + * Todo: This is kind of a mess, and it makes all these event handlers show + * up on Layers and Map. Leaflet itself is based around Evented, and @types/leaflet + * makes this very hard to work around. + * + */ + interface Evented { + /****************************************** + * + * AVAILABLE ON MAP + LAYER, THESE ARE OK ON EVENTED. + * + ********************************************/ + + /** Fired when a layer is removed via Removal Mode. */ + on(type: 'pm:remove', fn: PM.RemoveEventHandler): this; + once(type: 'pm:remove', fn: PM.RemoveEventHandler): this; + off(type: 'pm:remove', fn?: PM.RemoveEventHandler): this; + + /** Fired when the layer being cut. Draw+Edit Mode */ + on(type: 'pm:cut', fn: PM.CutEventHandler): this; + once(type: 'pm:cut', fn: PM.CutEventHandler): this; + off(type: 'pm:cut', fn?: PM.CutEventHandler): this; + + /** Fired when rotation is enabled for a layer. */ + on(type: 'pm:rotateenable', fn: PM.RotateEnableEventHandler): this; + once(type: 'pm:rotateenable', fn: PM.RotateEnableEventHandler): this; + off(type: 'pm:rotateenable', fn?: PM.RotateEnableEventHandler): this; + + /** Fired when rotation is disabled for a layer. */ + on(type: 'pm:rotatedisable', fn: PM.RotateDisableEventHandler): this; + once(type: 'pm:rotatedisable', fn: PM.RotateDisableEventHandler): this; + off(type: 'pm:rotatedisable', fn?: PM.RotateDisableEventHandler): this; + + /** Fired when rotation starts on a layer. */ + on(type: 'pm:rotatestart', fn: PM.RotateStartEventHandler): this; + once(type: 'pm:rotatestart', fn: PM.RotateStartEventHandler): this; + off(type: 'pm:rotatestart', fn?: PM.RotateStartEventHandler): this; + + /** Fired when a layer is rotated. */ + on(type: 'pm:rotate', fn: PM.RotateEventHandler): this; + once(type: 'pm:rotate', fn: PM.RotateEventHandler): this; + off(type: 'pm:rotate', fn?: PM.RotateEventHandler): this; + + /** Fired when rotation ends on a layer. */ + on(type: 'pm:rotateend', fn: PM.RotateEndEventHandler): this; + once(type: 'pm:rotateend', fn: PM.RotateEndEventHandler): this; + off(type: 'pm:rotateend', fn?: PM.RotateEndEventHandler): this; + + /****************************************** + * + * TODO: DRAW/EDIT MODE EVENTS LAYER ONLY + * + ********************************************/ + + /** Fired during a marker move/drag. */ + on(type: 'pm:snapdrag', fn: PM.SnapEventHandler): this; + once(type: 'pm:snapdrag', fn: PM.SnapEventHandler): this; + off(type: 'pm:snapdrag', fn?: PM.SnapEventHandler): this; + + /** Fired when a vertex is snapped. */ + on(type: 'pm:snap', fn: PM.SnapEventHandler): this; + once(type: 'pm:snap', fn: PM.SnapEventHandler): this; + off(type: 'pm:snap', fn?: PM.SnapEventHandler): this; + + /** Fired when a vertex is unsnapped. */ + on(type: 'pm:unsnap', fn: PM.SnapEventHandler): this; + once(type: 'pm:unsnap', fn: PM.SnapEventHandler): this; + off(type: 'pm:unsnap', fn?: PM.SnapEventHandler): this; + + /** Called when the center of a circle is placed/moved. */ + on(type: 'pm:centerplaced', fn: PM.CenterPlacedEventHandler): this; + once(type: 'pm:centerplaced', fn: PM.CenterPlacedEventHandler): this; + off(type: 'pm:centerplaced', fn?: PM.CenterPlacedEventHandler): this; + + /****************************************** + * + * TODO: CUT/EDIT MODE EVENTS LAYER ONLY + * + ********************************************/ + + /** Fired when a layer is edited. */ + on(type: 'pm:edit', fn: PM.EditEventHandler): this; + once(type: 'pm:edit', fn: PM.EditEventHandler): this; + off(type: 'pm:edit', fn?: PM.EditEventHandler): this; + + /****************************************** + * + * TODO: DRAW MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Drawing Mode is toggled. */ + on( + type: 'pm:globaldrawmodetoggled', + fn: PM.GlobalDrawModeToggledEventHandler, + context?: any + ): L.Evented; + once( + type: 'pm:globaldrawmodetoggled', + fn: PM.GlobalDrawModeToggledEventHandler, + context?: any + ): L.Evented; + off( + type: 'pm:globaldrawmodetoggled', + fn?: PM.GlobalDrawModeToggledEventHandler, + context?: any + ): L.Evented; + + /** Called when drawing mode is enabled. Payload includes the shape type and working layer. */ + on( + type: 'pm:drawstart', + fn: PM.DrawStartEventHandler, + context?: any + ): L.Evented; + once( + type: 'pm:drawstart', + fn: PM.DrawStartEventHandler, + context?: any + ): L.Evented; + off( + type: 'pm:drawstart', + fn?: PM.DrawStartEventHandler, + context?: any + ): L.Evented; + + /** Called when drawing mode is disabled. Payload includes the shape type. */ + on( + type: 'pm:drawend', + fn: PM.DrawEndEventHandler, + context?: any + ): L.Evented; + once( + type: 'pm:drawend', + fn: PM.DrawEndEventHandler, + context?: any + ): L.Evented; + off( + type: 'pm:drawend', + fn?: PM.DrawEndEventHandler, + context?: any + ): L.Evented; + + /** Called when drawing mode is disabled. Payload includes the shape type. */ + on(type: 'pm:create', fn: PM.CreateEventHandler, context?: any): L.Evented; + once( + type: 'pm:create', + fn: PM.CreateEventHandler, + context?: any + ): L.Evented; + off( + type: 'pm:create', + fn?: PM.CreateEventHandler, + context?: any + ): L.Evented; + + /****************************************** + * + * TODO: DRAW MODE EVENTS ON LAYER ONLY + * + ********************************************/ + + /** Called when a new vertex is added. */ + on(type: 'pm:vertexadded', fn: PM.VertexAddedEventHandler): this; + once(type: 'pm:vertexadded', fn: PM.VertexAddedEventHandler): this; + off(type: 'pm:vertexadded', fn?: PM.VertexAddedEventHandler): this; + + /****************************************** + * + * TODO: EDIT MODE EVENTS ON LAYER ONLY + * + ********************************************/ + + /** Fired when edit mode is disabled and a layer is edited and its coordinates have changed. */ + on(type: 'pm:update', fn: PM.UpdateEventHandler): this; + once(type: 'pm:update', fn: PM.UpdateEventHandler): this; + off(type: 'pm:update', fn?: PM.UpdateEventHandler): this; + + /** Fired when edit mode on a layer is enabled. */ + on(type: 'pm:enable', fn: PM.EnableEventHandler): this; + once(type: 'pm:enable', fn: PM.EnableEventHandler): this; + off(type: 'pm:enable', fn?: PM.EnableEventHandler): this; + + /** Fired when edit mode on a layer is disabled. */ + on(type: 'pm:disable', fn: PM.DisableEventHandler): this; + once(type: 'pm:disable', fn: PM.DisableEventHandler): this; + off(type: 'pm:disable', fn?: PM.DisableEventHandler): this; + + /** Fired when a vertex is added. */ + on(type: 'pm:vertexadded', fn: PM.VertexAddedEventHandler2): this; + once(type: 'pm:vertexadded', fn: PM.VertexAddedEventHandler2): this; + off(type: 'pm:vertexadded', fn?: PM.VertexAddedEventHandler2): this; + + /** Fired when a vertex is removed. */ + on(type: 'pm:vertexremoved', fn: PM.VertexRemovedEventHandler): this; + once(type: 'pm:vertexremoved', fn: PM.VertexRemovedEventHandler): this; + off(type: 'pm:vertexremoved', fn?: PM.VertexRemovedEventHandler): this; + + /** Fired when a vertex is clicked. */ + on(type: 'pm:vertexclick', fn: PM.VertexClickEventHandler): this; + once(type: 'pm:vertexclick', fn: PM.VertexClickEventHandler): this; + off(type: 'pm:vertexclick', fn?: PM.VertexClickEventHandler): this; + + /** Fired when dragging of a marker which corresponds to a vertex starts. */ + on(type: 'pm:markerdragstart', fn: PM.MarkerDragStartEventHandler): this; + once(type: 'pm:markerdragstart', fn: PM.MarkerDragStartEventHandler): this; + off(type: 'pm:markerdragstart', fn?: PM.MarkerDragStartEventHandler): this; + + /** Fired when dragging a vertex-marker. */ + on(type: 'pm:markerdrag', fn: PM.MarkerDragEventHandler): this; + once(type: 'pm:markerdrag', fn: PM.MarkerDragEventHandler): this; + off(type: 'pm:markerdrag', fn?: PM.MarkerDragEventHandler): this; + + /** Fired when dragging of a vertex-marker ends. */ + on(type: 'pm:markerdragend', fn: PM.MarkerDragEndEventHandler): this; + once(type: 'pm:markerdragend', fn: PM.MarkerDragEndEventHandler): this; + off(type: 'pm:markerdragend', fn?: PM.MarkerDragEndEventHandler): this; + + /** Fired when coords of a layer are reset. E.g. by self-intersection.. */ + on(type: 'pm:layerreset', fn: PM.LayerResetEventHandler): this; + once(type: 'pm:layerreset', fn: PM.LayerResetEventHandler): this; + off(type: 'pm:layerreset', fn?: PM.LayerResetEventHandler): this; + + /** When allowSelfIntersection: false, this event is fired as soon as a self-intersection is detected. */ + on(type: 'pm:intersect', fn: PM.IntersectEventHandler): this; + once(type: 'pm:intersect', fn: PM.IntersectEventHandler): this; + off(type: 'pm:intersect', fn?: PM.IntersectEventHandler): this; + + /****************************************** + * + * TODO: EDIT MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Edit Mode is toggled. */ + on( + type: 'pm:globaleditmodetoggled', + fn: PM.GlobalEditModeToggledEventHandler + ): this; + once( + type: 'pm:globaleditmodetoggled', + fn: PM.GlobalEditModeToggledEventHandler + ): this; + off( + type: 'pm:globaleditmodetoggled', + fn?: PM.GlobalEditModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: DRAG MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Drag Mode is toggled. */ + on( + type: 'pm:globaldragmodetoggled', + fn: PM.GlobalDragModeToggledEventHandler + ): this; + once( + type: 'pm:globaldragmodetoggled', + fn: PM.GlobalDragModeToggledEventHandler + ): this; + off( + type: 'pm:globaldragmodetoggled', + fn?: PM.GlobalDragModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: DRAG MODE EVENTS ON LAYER ONLY + * + ********************************************/ + + /** Fired when a layer starts being dragged. */ + on(type: 'pm:dragstart', fn: PM.DragStartEventHandler): this; + once(type: 'pm:dragstart', fn: PM.DragStartEventHandler): this; + off(type: 'pm:dragstart', fn?: PM.DragStartEventHandler): this; + + /** Fired when a layer is dragged. */ + on(type: 'pm:drag', fn: PM.DragEventHandler): this; + once(type: 'pm:drag', fn: PM.DragEventHandler): this; + off(type: 'pm:drag', fn?: PM.DragEventHandler): this; + + /** Fired when a layer stops being dragged. */ + on(type: 'pm:dragend', fn: PM.DragEndEventHandler): this; + once(type: 'pm:dragend', fn: PM.DragEndEventHandler): this; + off(type: 'pm:dragend', fn?: PM.DragEndEventHandler): this; + + /****************************************** + * + * TODO: REMOVE MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Removal Mode is toggled. */ + on( + type: 'pm:globalremovalmodetoggled', + fn: PM.GlobalRemovalModeToggledEventHandler + ): this; + once( + type: 'pm:globalremovalmodetoggled', + fn: PM.GlobalRemovalModeToggledEventHandler + ): this; + off( + type: 'pm:globalremovalmodetoggled', + fn?: PM.GlobalRemovalModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: CUT MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when a layer is removed via Removal Mode. */ + on( + type: 'pm:globalcutmodetoggled', + fn: PM.GlobalCutModeToggledEventHandler + ): this; + once( + type: 'pm:globalcutmodetoggled', + fn: PM.GlobalCutModeToggledEventHandler + ): this; + off( + type: 'pm:globalcutmodetoggled', + fn?: PM.GlobalCutModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: ROTATE MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Rotate Mode is toggled. */ + on( + type: 'pm:globalrotatemodetoggled', + fn: PM.GlobalRotateModeToggledEventHandler + ): this; + once( + type: 'pm:globalrotatemodetoggled', + fn: PM.GlobalRotateModeToggledEventHandler + ): this; + off( + type: 'pm:globalrotatemodetoggled', + fn?: PM.GlobalRotateModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: TRANSLATION EVENTS ON MAP ONLY + * + ********************************************/ + + /** Standard Leaflet event. Fired when any layer is removed. */ + on(type: 'pm:langchange', fn: PM.LangChangeEventHandler): this; + once(type: 'pm:langchange', fn: PM.LangChangeEventHandler): this; + off(type: 'pm:langchange', fn?: PM.LangChangeEventHandler): this; + + /****************************************** + * + * TODO: CONTROL EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when a Toolbar button is clicked. */ + on(type: 'pm:buttonclick', fn: PM.ButtonClickEventHandler): this; + once(type: 'pm:buttonclick', fn: PM.ButtonClickEventHandler): this; + off(type: 'pm:buttonclick', fn?: PM.ButtonClickEventHandler): this; + + /** Fired when a Toolbar action is clicked. */ + on(type: 'pm:actionclick', fn: PM.ActionClickEventHandler): this; + once(type: 'pm:actionclick', fn: PM.ActionClickEventHandler): this; + off(type: 'pm:actionclick', fn?: PM.ActionClickEventHandler): this; + + /****************************************** + * + * TODO: Keyboard EVENT ON MAP ONLY + * + ********************************************/ + + /** Fired when `keydown` or `keyup` on the document is fired. */ + on(type: 'pm:keyevent', fn: PM.KeyboardKeyEventHandler): this; + once(type: 'pm:keyevent', fn: PM.KeyboardKeyEventHandler): this; + off(type: 'pm:keyevent', fn?: PM.KeyboardKeyEventHandler): this; + } + + namespace PM { + /** Supported shape names. 'ImageOverlay' is in Edit Mode only. Also accepts custom shape name. */ + type SUPPORTED_SHAPES = + | 'Marker' + | 'Circle' + | 'Line' + | 'Rectangle' + | 'Polygon' + | 'Cut' + | 'CircleMarker' + | 'ImageOverlay' + | string; + + /** + * Changes default registration of leaflet-geoman on leaflet layers. + * + * @param optIn - if true, a layers pmIgnore property has to be set to false to get initiated. + */ + function setOptIn(optIn: boolean): void; + + /** + * Enable leaflet-geoman on an ignored layer. + * + * @param layer - re-reads layer.options.pmIgnore to initialize leaflet-geoman. + */ + function reInitLayer(layer: L.Layer): void; + + /** + * PM map interface. + */ + interface PMMap + extends PMDrawMap, + PMEditMap, + PMDragMap, + PMRemoveMap, + PMCutMap, + PMRotateMap { + Toolbar: PMMapToolbar; + + Keyboard: PMMapKeyboard; + + /** Adds the Toolbar to the map. */ + addControls(options?: ToolbarOptions): void; + + /** Toggle the visiblity of the Toolbar. */ + removeControls(): void; + + /** Returns true if the Toolbar is visible on the map. */ + controlsVisible(): boolean; + + /** Toggle the visiblity of the Toolbar. */ + toggleControls(): void; + + setLang( + lang: + | 'cz' + | 'da' + | 'de' + | 'el' + | 'en' + | 'es' + | 'fa' + | 'fr' + | 'hu' + | 'id' + | 'it' + | 'nl' + | 'no' + | 'pl' + | 'pt_br' + | 'ro' + | 'ru' + | 'sv' + | 'tr' + | 'ua' + | 'zh' + | 'zh_tw', + customTranslations?: Translations, + fallbackLanguage?: string + ): void; + + /** Set globalOptions and apply them. */ + setGlobalOptions(options: GlobalOptions): void; + + /** Apply the current globalOptions to all existing layers. */ + applyGlobalOptions(): void; + + /** Returns the globalOptions. */ + getGlobalOptions(): GlobalOptions; + } + + class Translations { + tooltips?: { + placeMarker?: string; + firstVertex?: string; + continueLine?: string; + finishLine?: string; + finishPoly?: string; + finishRect?: string; + startCircle?: string; + finishCircle?: string; + placeCircleMarker?: string; + }; + + actions?: { + finish?: string; + cancel?: string; + removeLastVertex?: string; + }; + + buttonTitles?: { + drawMarkerButton?: string; + drawPolyButton?: string; + drawLineButton?: string; + drawCircleButton?: string; + drawRectButton?: string; + editButton?: string; + dragButton?: string; + cutButton?: string; + deleteButton?: string; + drawCircleMarkerButton?: string; + }; + } + + type ACTION_NAMES = 'cancel' | 'removeLastVertex' | 'finish' | 'finishMode'; + + class Action { + text: string; + onClick?: (e: any) => void; + } + + type TOOLBAR_CONTROL_ORDER = + | 'drawMarker' + | 'drawCircleMarker' + | 'drawPolyline' + | 'drawRectangle' + | 'drawPolygon' + | 'drawCircle' + | 'editMode' + | 'dragMode' + | 'cutPolygon' + | 'removalMode' + | 'rotateMode' + | string; + + interface PMMapToolbar { + /** Pass an array of button names to reorder the buttons in the Toolbar. */ + changeControlOrder(order?: TOOLBAR_CONTROL_ORDER[]): void; + + /** Receive the current order with. */ + getControlOrder(): TOOLBAR_CONTROL_ORDER[]; + + /** The position of a block (draw, edit, custom, options⭐) in the Toolbar can be changed. If not set, the value */ + /** from position of the Toolbar is taken. */ + setBlockPosition( + block: 'draw' | 'edit' | 'custom' | 'options', + position: L.ControlPosition + ): void; + + /** Returns a Object with the positions for all blocks */ + getBlockPositions(): BlockPositions; + + /** To add a custom Control to the Toolbar */ + createCustomControl(options: CustomControlOptions): void; + + /** Creates a copy of a draw Control. Returns the drawInstance and the control. */ + copyDrawControl( + copyInstance: string, + options?: CustomControlOptions + ): void; + + /** Change the actions of an existing button. */ + changeActionsOfControl( + name: string, + actions: (ACTION_NAMES | Action)[] + ): void; + + /** Disable button by control name */ + setButtonDisabled(name: TOOLBAR_CONTROL_ORDER, state: boolean): void; + } + + type KEYBOARD_EVENT_TYPE = 'current' | 'keydown' | 'keyup'; + + interface PMMapKeyboard { + /** Pass an array of button names to reorder the buttons in the Toolbar. */ + getLastKeyEvent(type: KEYBOARD_EVENT_TYPE[]): KeyboardKeyEventHandler; + + /** Returns the current pressed key. [KeyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key). */ + getPressedKey(): string; + + /** Returns true if the `Shift` key is currently pressed. */ + isShiftKeyPressed(): boolean; + + /** Returns true if the `Alt` key is currently pressed. */ + isAltKeyPressed(): boolean; + + /** Returns true if the `Ctrl` key is currently pressed. */ + isCtrlKeyPressed(): boolean; + + /** Returns true if the `Meta` key is currently pressed. */ + isMetaKeyPressed(): boolean; + } + + interface Button { + /** Actions */ + actions: (ACTION_NAMES | Action)[]; + + /** Function fired after clicking the control. */ + afterClick: () => void; + + /** CSS class with the Icon. */ + className: string; + + /** If true, other buttons will be disabled on click (default: true) */ + disableOtherButtons: boolean; + + /** Control can be toggled. */ + doToggle: boolean; + + /** Extending Class f. ex. Line, Polygon, ... L.PM.Draw.EXTENDINGCLASS */ + jsClass: string; + + /** Function fired when clicking the control. */ + onClick: () => void; + + position: L.ControlPosition; + + /** Text showing when you hover the control. */ + title: string; + + /** Toggle state true -> enabled, false -> disabled (default: false) */ + toggleStatus: boolean; + + /** Block of the control. 'options' is ⭐ only. */ + tool?: 'draw' | 'edit' | 'custom' | 'options'; + } + + interface CustomControlOptions { + /** Name of the control */ + name: string; + + /** Block of the control. 'options' is ⭐ only. */ + block?: 'draw' | 'edit' | 'custom' | 'options'; + + /** Text showing when you hover the control. */ + title?: string; + + /** CSS class with the Icon. */ + className?: string; + + /** Function fired when clicking the control. */ + onClick?: () => void; + + /** Function fired after clicking the control. */ + afterClick?: () => void; + + /** Actions */ + actions?: (ACTION_NAMES | Action)[]; + + /** Control can be toggled. */ + toggle?: boolean; + + /** Control is disabled. */ + disabled?: boolean; + } + + type PANE = + | 'mapPane' + | 'tilePane' + | 'overlayPane' + | 'shadowPane' + | 'markerPane' + | 'tooltipPane' + | 'popupPane' + | string; + + interface GlobalOptions extends DrawModeOptions, EditModeOptions { + /** Add the created layers to a layergroup instead to the map. */ + layerGroup?: L.Map | L.LayerGroup; + + /** Prioritize the order of snapping. Default: ['Marker','CircleMarker','Circle','Line','Polygon','Rectangle']. */ + snappingOrder: SUPPORTED_SHAPES[]; + + /** Defines in which panes the layers and helper vertices are created. Default: */ + /** { vertexPane: 'markerPane', layerPane: 'overlayPane', markerPane: 'markerPane' } */ + panes: { vertexPane: PANE; layerPane: PANE; markerPane: PANE }; + } + + interface PMDrawMap { + + /** Draw */ + Draw: Draw; + /** Enable Draw Mode with the passed shape. */ + enableDraw(shape: SUPPORTED_SHAPES, options?: DrawModeOptions): void; + + /** Disable all drawing */ + disableDraw(shape?: SUPPORTED_SHAPES): void; + + /** Returns true if global Draw Mode is enabled. false when disabled. */ + globalDrawModeEnabled(): boolean; + + /** Customize the style of the drawn layer. Only for L.Path layers. */ + /** Shapes can be excluded with a ignoreShapes array or merged with the current style with merge: true in optionsModifier. */ + setPathOptions( + options: L.PathOptions, + optionsModifier?: { ignoreShapes?: SUPPORTED_SHAPES[]; merge?: boolean } + ): void; + + /** Returns all Geoman layers on the map as array. Pass true to get a L.FeatureGroup. */ + getGeomanLayers(asFeatureGroup?: boolean): L.FeatureGroup | L.Layer[]; + + /** Returns all Geoman draw layers on the map as array. Pass true to get a L.FeatureGroup. */ + getGeomanDrawLayers(asFeatureGroup?: boolean): L.FeatureGroup | L.Layer[]; + } + + interface PMEditMap { + /** Enables edit mode. The passed options are preserved, even when the mode is enabled via the Toolbar */ + enableGlobalEditMode(options?: EditModeOptions): void; + + /** Disables global edit mode. */ + disableGlobalEditMode(): void; + + /** Toggles global edit mode. */ + toggleGlobalEditMode(options?: EditModeOptions): void; + + /** Returns true if global edit mode is enabled. false when disabled. */ + globalEditModeEnabled(): boolean; + } + + interface PMDragMap { + /** Enables global drag mode. */ + enableGlobalDragMode(): void; + + /** Disables global drag mode. */ + disableGlobalDragMode(): void; + + /** Toggles global drag mode. */ + toggleGlobalDragMode(): void; + + /** Returns true if global drag mode is enabled. false when disabled. */ + globalDragModeEnabled(): boolean; + } + + interface PMRemoveMap { + /** Enables global removal mode. */ + enableGlobalRemovalMode(): void; + + /** Disables global removal mode. */ + disableGlobalRemovalMode(): void; + + /** Toggles global removal mode. */ + toggleGlobalRemovalMode(): void; + + /** Returns true if global removal mode is enabled. false when disabled. */ + globalRemovalModeEnabled(): boolean; + } + + interface PMCutMap { + /** Enables global cut mode. */ + enableGlobalCutMode(options?: CutModeOptions): void; + + /** Disables global cut mode. */ + disableGlobalCutMode(): void; + + /** Toggles global cut mode. */ + toggleGlobalCutMode(options?: CutModeOptions): void; + + /** Returns true if global cut mode is enabled. false when disabled. */ + globalCutModeEnabled(): boolean; + } + + interface PMRotateMap { + /** Enables global rotate mode. */ + enableGlobalRotateMode(): void; + + /** Disables global rotate mode. */ + disableGlobalRotateMode(): void; + + /** Toggles global rotate mode. */ + toggleGlobalRotateMode(): void; + + /** Returns true if global rotate mode is enabled. false when disabled. */ + globalRotateModeEnabled(): boolean; + } + + interface PMRotateLayer { + /** Enables rotate mode on the layer. */ + enableRotate(): void; + + /** Disables rotate mode on the layer. */ + disableRotate(): void; + + /** Toggles rotate mode on the layer. */ + rotateEnabled(): void; + + /** Rotates the layer by x degrees. */ + rotateLayer(degrees: number): void; + + /** Rotates the layer to x degrees. */ + rotateLayerToAngle(degrees: number): void; + + /** Returns the angle of the layer in degrees. */ + getAngle(): number; + } + + interface Draw { + /** Array of available shapes. */ + getShapes(): SUPPORTED_SHAPES[]; + + /** Returns the active shape. */ + getActiveShape(): SUPPORTED_SHAPES; + + /** Set path options */ + setPathOptions(options: L.PathOptions): void; + + /** Set options */ + setOptions(options: DrawModeOptions): void; + + /** Get options */ + getOptions(): DrawModeOptions; + } + + interface CutModeOptions { + allowSelfIntersection?: boolean; + } + + type VertexValidationHandler = (e: { + layer: L.Layer; + marker: L.Marker; + event: any; + }) => boolean; + + interface EditModeOptions { + /** Enable snapping to other layers vertices for precision drawing. Can be disabled by holding the ALT key (default:true). */ + snappable?: boolean; + + /** The distance to another vertex when a snap should happen (default:20). */ + snapDistance?: number; + + /** Allow self intersections (default:true). */ + allowSelfIntersection?: boolean; + + /** Allow self intersections (default:true). */ + allowSelfIntersectionEdit?: boolean; + + /** Disable the removal of markers via right click / vertices via removeVertexOn. (default:false). */ + preventMarkerRemoval?: boolean; + + /** If true, vertex removal that cause a layer to fall below their minimum required vertices will remove the entire layer. */ + /** If false, these vertices can't be removed. Minimum vertices are 2 for Lines and 3 for Polygons (default:true). */ + removeLayerBelowMinVertexCount?: boolean; + + /** Defines which layers should dragged with this layer together. */ + /** true syncs all layers in the same LayerGroup(s) or you pass an `Array` of layers to sync. (default:false). */ + syncLayersOnDrag?: L.Layer[] | boolean; + + /** Edit-Mode for the layer can disabled (`pm.enable()`). (default:true). */ + allowEditing?: boolean; + + /** Removing can be disabled for the layer. (default:true). */ + allowRemoval?: boolean; + + /** Layer can be prevented from cutting. (default:true). */ + allowCutting?: boolean; + + /** Layer can be prevented from rotation. (default:true). */ + allowRotation?: boolean; + + /** Dragging can be disabled for the layer. (default:true). */ + draggable?: boolean; + + /** Leaflet layer event to add a vertex to a Line or Polygon, like dblclick. (default:click). */ + addVertexOn?: + | 'click' + | 'dblclick' + | 'mousedown' + | 'mouseover' + | 'mouseout' + | 'contextmenu'; + + /** A function for validation if a vertex (of a Line / Polygon) is allowed to add. */ + /** It passes a object with `[layer, marker, event}`. For example to check if the layer */ + /** has a certain property or if the `Ctrl` key is pressed. (default:undefined). */ + addVertexValidation?: undefined | VertexValidationHandler; + + /** Leaflet layer event to remove a vertex from a Line or Polygon, like dblclick. (default:contextmenu). */ + removeVertexOn?: + | 'click' + | 'dblclick' + | 'mousedown' + | 'mouseover' + | 'mouseout' + | 'contextmenu'; + + /** A function for validation if a vertex (of a Line / Polygon) is allowed to remove. */ + /** It passes a object with `[layer, marker, event}`. For example to check if the layer has a certain property */ + /** or if the `Ctrl` key is pressed. */ + removeVertexValidation?: undefined | VertexValidationHandler; + + /** A function for validation if a vertex / helper-marker is allowed to move / drag. It passes a object with */ + /** `[layer, marker, event}`. For example to check if the layer has a certain property or if the `Ctrl` key is pressed. */ + moveVertexValidation?: undefined | VertexValidationHandler; + + /** Shows only n markers closest to the cursor. Use -1 for no limit (default:-1). */ + limitMarkersToCount?: number; + + /** Shows markers when under the given zoom level ⭐ */ + limitMarkersToZoom?: number; + + /** Shows only markers in the viewport ⭐ */ + limitMarkersToViewport?: boolean; + + /** Shows markers only after the layer was clicked ⭐ */ + limitMarkersToClick?: boolean; + + /** Pin shared vertices/markers together during edit ⭐ */ + pinning?: boolean; + + /** Hide the middle Markers in edit mode from Polyline and Polygon. */ + hideMiddleMarkers?: boolean; + } + + interface DrawModeOptions { + /** Enable snapping to other layers vertices for precision drawing. Can be disabled by holding the ALT key (default:true). */ + snappable?: boolean; + + /** The distance to another vertex when a snap should happen (default:20). */ + snapDistance?: number; + + /** Allow snapping in the middle of two vertices (middleMarker)(default:false). */ + snapMiddle?: boolean; + + /** Allow snapping between two vertices. (default: true) */ + snapSegment?: boolean; + + /** Require the last point of a shape to be snapped. (default: false). */ + requireSnapToFinish?: boolean; + + /** Show helpful tooltips for your user (default:true). */ + tooltips?: boolean; + + /** Allow self intersections (default:true). */ + allowSelfIntersection?: boolean; + + /** Leaflet path options for the lines between drawn vertices/markers. (default:{color:'red'}). */ + templineStyle?: L.PathOptions; + + /** Leaflet path options for the helper line between last drawn vertex and the cursor. (default:{color:'red',dashArray:[5,5]}). */ + hintlineStyle?: L.PathOptions; + + /** Leaflet path options for the drawn layer (Only for L.Path layers). (default:null). */ + pathOptions?: L.PathOptions; + + /** Leaflet marker options (only for drawing markers). (default:{draggable:true}). */ + markerStyle?: L.MarkerOptions; + + /** Show a marker at the cursor (default:true). */ + cursorMarker?: boolean; + + /** Leaflet layer event to finish the drawn shape (default:null). */ + finishOn?: + | null + | 'click' + | 'dblclick' + | 'mousedown' + | 'mouseover' + | 'mouseout' + | 'contextmenu' + | 'snap'; + + /** Hide the middle Markers in edit mode from Polyline and Polygon. (default:false). */ + hideMiddleMarkers?: boolean; + + /** Set the min radius of a Circle. (default:null). */ + minRadiusCircle?: number; + + /** Set the max radius of a Circle. (default:null). */ + maxRadiusCircle?: number; + + /** Set the min radius of a CircleMarker when editable is active. (default:null). */ + minRadiusCircleMarker?: number; + + /** Set the max radius of a CircleMarker when editable is active. (default:null). */ + maxRadiusCircleMarker?: number; + + /** Makes a CircleMarker editable like a Circle (default:false). */ + editable?: boolean; + + /** Markers and CircleMarkers are editable during the draw-session */ + /** (you can drag them around immediately after drawing them) (default:true). */ + markerEditable?: boolean; + + /** Draw-Mode stays enabled after finishing a layer to immediately draw the next layer. */ + /** Defaults to true for Markers and CircleMarkers and false for all other layers. */ + continueDrawing?: boolean; + + /** Angel of rectangle. */ + rectangleAngle?: number; + + /** Cut-Mode: Only the passed layers can be cut. Cutted layers are removed from the */ + /** Array until no layers are left anymore and cutting is working on all layers again. (Default: []) */ + layersToCut?: L.Layer[]; + } + + /** + * PM toolbar options. + */ + interface ToolbarOptions { + /** Toolbar position. */ + position?: L.ControlPosition; + + /** The position of each block can be customized. If not set, the value from position is taken. */ + positions?: BlockPositions; + + /** Adds button to draw Markers (default:true) */ + drawMarker?: boolean; + + /** Adds button to draw CircleMarkers (default:true) */ + drawCircleMarker?: boolean; + + /** Adds button to draw Line (default:true) */ + drawPolyline?: boolean; + + /** Adds button to draw Rectangle (default:true) */ + drawRectangle?: boolean; + + /** Adds button to draw Polygon (default:true) */ + drawPolygon?: boolean; + + /** Adds button to draw Circle (default:true) */ + drawCircle?: boolean; + + /** Adds button to toggle edit mode for all layers (default:true) */ + editMode?: boolean; + + /** Adds button to toggle drag mode for all layers (default:true) */ + dragMode?: boolean; + + /** Adds button to cut a hole in a polygon or line (default:true) */ + cutPolygon?: boolean; + + /** Adds a button to remove layers (default:true) */ + removalMode?: boolean; + + /** Adds a button to rotate layers (default:true) */ + rotateMode?: boolean; + + /** All buttons will be displayed as one block Customize Controls (default:false) */ + oneBlock?: boolean; + + /** Shows all draw buttons / buttons in the draw block (default:true) */ + drawControls?: boolean; + + /** Shows all edit buttons / buttons in the edit block (default:true) */ + editControls?: boolean; + + /** Shows all buttons in the custom block (default:true) */ + customControls?: boolean; + + /** Shows all options buttons / buttons in the option block ⭐ */ + optionsControls?: boolean; + + /** Adds a button to toggle the Pinning Option ⭐ */ + pinningOption?: boolean; + + /** Adds a button to toggle the Snapping Option ⭐ */ + snappingOption?: boolean; + } + + /** the position of each block. */ + interface BlockPositions { + /** Draw control position (default:''). '' also refers to this position. */ + draw?: L.ControlPosition; + + /** Edit control position (default:''). */ + edit?: L.ControlPosition; + + /** Custom control position (default:''). */ + custom?: L.ControlPosition; + + /** Options control position (default:'') ⭐ */ + options?: L.ControlPosition; + } + + interface PMEditLayer { + /** Enables edit mode. The passed options are preserved, even when the mode is enabled via the Toolbar */ + enable(options?: EditModeOptions): void; + + /** Sets layer options */ + setOptions(options?: EditModeOptions): void; + + /** Gets layer options */ + getOptions(): EditModeOptions; + + /** Disables edit mode. */ + disable(): void; + + /** Toggles edit mode. Passed options are preserved. */ + toggleEdit(options?: EditModeOptions): void; + + /** Returns true if edit mode is enabled. false when disabled. */ + enabled(): boolean; + + /** Returns true if Line or Polygon has a self intersection. */ + hasSelfIntersection(): boolean; + + /** Removes the layer with the same checks as GlobalRemovalMode. */ + remove(): void; + } + + interface PMDragLayer { + /** Enables dragging for the layer. */ + enableLayerDrag(): void; + + /** Disables dragging for the layer. */ + disableLayerDrag(): void; + + /** Returns if the layer is currently dragging. */ + dragging(): boolean; + + /** Returns if drag mode is enabled for the layer. */ + layerDragEnabled(): boolean; + } + + interface PMLayer extends PMRotateLayer, PMEditLayer, PMDragLayer { + /** Get shape of the layer. */ + getShape(): SUPPORTED_SHAPES; + } + + interface PMLayerGroup { + /** Enables edit mode for all child layers. The passed options are preserved, even when the mode is enabled via the Toolbar */ + enable(options?: EditModeOptions): void; + + /** Disable edit mode for all child layers. */ + disable(): void; + + /** Returns if minimum one layer is enabled. */ + enabled(): boolean; + + /** Toggle enable / disable on all layers. */ + toggleEdit(options?: EditModeOptions): void; + + /** Returns the layers of the LayerGroup. `deep=true` return also the children of LayerGroup children. */ + /** `filterGeoman=true` filter out layers that don't have Leaflet-Geoman or temporary stuff. */ + /** `filterGroupsOut=true` does not return the LayerGroup layers self. */ + /** (Default: `deep=false`,`filterGeoman=true`, `filterGroupsOut=true` ) */ + getLayers( + deep?: boolean, + filterGeoman?: boolean, + filterGroupsOut?: boolean + ): L.Layer[]; + + /** Apply Leaflet-Geoman options to all children. The passed options are preserved, even when the mode is enabled via the Toolbar */ + setOptions(options?: EditModeOptions): void; + + /** Returns the options of the LayerGroup. */ + getOptions(): EditModeOptions; + + /** Returns if currently a layer in the LayerGroup is dragging. */ + dragging(): boolean; + } + + namespace Utils { + /** Returns the translation of the passed path. path = json-string f.ex. tooltips.placeMarker */ + function getTranslation(path: string): string; + + /** Returns the middle LatLng between two LatLngs */ + function calcMiddleLatLng( + map: L.Map, + latlng1: L.LatLng, + latlng2: L.LatLng + ): L.LatLng; + + /** Returns all layers that are available for Geoman */ + function findLayers(map: L.Map): L.Layer[]; + + /** Converts a circle into a polygon with default 60 sides. For CRS.Simple maps `withBearing` needs to be false */ + function circleToPolygon( + circle: L.Circle, + sides?: number, + withBearing?: boolean + ): L.Polygon; + + /** Converts a px-radius (CircleMarker) to meter-radius (Circle). */ + /** The center LatLng is needed because the earth has different projections on different places. */ + function pxRadiusToMeterRadius( + radiusInPx: number, + map: L.Map, + center: L.LatLng + ): number; + } + + /** + * DRAW MODE MAP EVENT HANDLERS + */ + + export type GlobalDrawModeToggledEventHandler = (event: { + enabled: boolean; + shape: PM.SUPPORTED_SHAPES; + map: L.Map; + }) => void; + export type DrawStartEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + workingLayer: L.Layer; + }) => void; + export type DrawEndEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type CreateEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + + /** + * DRAW MODE LAYER EVENT HANDLERS + */ + + export type VertexAddedEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + workingLayer: L.Layer; + marker: L.Marker; + latlng: L.LatLng; + }) => void; + export type SnapEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + distance: number; + layer: L.Layer; + workingLayer: L.Layer; + marker: L.Marker; + layerInteractedWith: L.Layer; + segement: any; + snapLatLng: L.LatLng; + }) => void; + export type CenterPlacedEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + workingLayer: L.Layer; + latlng: L.LatLng; + }) => void; + + /** + * EDIT MODE LAYER EVENT HANDLERS + */ + + export type EditEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + export type UpdateEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + export type EnableEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + export type DisableEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + export type VertexAddedEventHandler2 = (e: { + layer: L.Layer; + indexPath: number; + latlng: L.LatLng; + marker: L.Marker; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type VertexRemovedEventHandler = (e: { + layer: L.Layer; + indexPath: number; + marker: L.Marker; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type VertexClickEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type MarkerDragStartEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type MarkerDragEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type MarkerDragEndEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + intersectionRest: boolean; + }) => void; + export type LayerResetEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type IntersectEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + intersection: L.LatLng; + }) => void; + + /** + * EDIT MODE MAP EVENT HANDLERS + */ + export type GlobalEditModeToggledEventHandler = (event: { + enabled: boolean; + map: L.Map; + }) => void; + + /** + * DRAG MODE MAP EVENT HANDLERS + */ + export type GlobalDragModeToggledEventHandler = (event: { + enabled: boolean; + map: L.Map; + }) => void; + + /** + * DRAG MODE LAYER EVENT HANDLERS + */ + export type DragStartEventHandler = (e: { + layer: L.Layer; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type DragEventHandler = (e: { + layer: L.Layer; + containerPoint: any; + latlng: L.LatLng; + layerPoint: L.Point; + originalEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type DragEndEventHandler = (e: { + layer: L.Layer; + shape: PM.SUPPORTED_SHAPES; + }) => void; + + /** + * REMOVE MODE LAYER EVENT HANDLERS + */ + + export type RemoveEventHandler = (e: { + layer: L.Layer; + shape: PM.SUPPORTED_SHAPES; + }) => void; + + /** + * REMOVE MODE MAP EVENT HANDLERS + */ + export type GlobalRemovalModeToggledEventHandler = (e: { + enabled: boolean; + map: L.Map; + }) => void; + + /** + * CUT MODE MAP EVENT HANDLERS + */ + export type GlobalCutModeToggledEventHandler = (e: { + enabled: boolean; + map: L.Map; + }) => void; + export type CutEventHandler = (e: { + layer: L.Layer; + originalLayer: L.Layer; + shape: PM.SUPPORTED_SHAPES; + }) => void; + + /** + * ROTATE MODE LAYER EVENT HANDLERS + */ + export type RotateEnableEventHandler = (e: { + layer: L.Layer; + helpLayer: L.Layer; + }) => void; + export type RotateDisableEventHandler = (e: { layer: L.Layer }) => void; + export type RotateStartEventHandler = (e: { + layer: L.Layer; + helpLayer: L.Layer; + startAngle: number; + originLatLngs: L.LatLng[]; + }) => void; + export type RotateEventHandler = (e: { + layer: L.Layer; + helpLayer: L.Layer; + startAngle: number; + angle: number; + angleDiff: number; + oldLatLngs: L.LatLng[]; + newLatLngs: L.LatLng[]; + }) => void; + export type RotateEndEventHandler = (e: { + layer: L.Layer; + helpLayer: L.Layer; + startAngle: number; + angle: number; + originLatLngs: L.LatLng[]; + newLatLngs: L.LatLng[]; + }) => void; + + /** + * ROTATE MODE MAP EVENT HANDLERS + */ + export type GlobalRotateModeToggledEventHandler = (e: { + enabled: boolean; + map: L.Map; + }) => void; + + /** + * TRANSLATION EVENT HANDLERS + */ + export type LangChangeEventHandler = (e: { + activeLang: string; + oldLang: string; + fallback: string; + translations: PM.Translations; + }) => void; + + /** + * CONTROL MAP EVENT HANDLERS + */ + export type ButtonClickEventHandler = (e: { + btnName: string; + button: PM.Button; + }) => void; + export type ActionClickEventHandler = (e: { + text: string; + action: string; + btnName: string; + button: PM.Button; + }) => void; + + /** + * KEYBOARD EVENT HANDLERS + */ + export type KeyboardKeyEventHandler = (e: { + focusOn: 'document' | 'map'; + eventType: 'keydown' | 'keyup'; + event: any; + }) => void; + } + namespace PM { interface PMMapToolbar { toggleButton( diff --git a/ui-ngx/tsconfig.json b/ui-ngx/tsconfig.json index 2243eae689..9963cadb75 100644 --- a/ui-ngx/tsconfig.json +++ b/ui-ngx/tsconfig.json @@ -23,7 +23,6 @@ "src/typings/jquery.flot.typings.d.ts", "src/typings/jquery.jstree.typings.d.ts", "src/typings/split.js.typings.d.ts", - "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.d.ts", "src/typings/leaflet-geoman-extend.d.ts" ], "paths": { From 8065684831045bc183bbc01bbf5f01caa66a73eb Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 7 Dec 2021 15:52:37 +0200 Subject: [PATCH 291/303] Fix resolve alias filter for query alias types --- ui-ngx/src/app/core/http/entity.service.ts | 24 ++++------------------ 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 3346d5ce83..2b71df5a0e 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -906,28 +906,12 @@ export class EntityService { result.entityFilter = deepClone(filter); return of(result); case AliasFilterType.relationsQuery: - result.stateEntity = filter.rootStateEntity; - let rootEntityType; - let rootEntityId; - if (result.stateEntity && stateEntityId) { - rootEntityType = stateEntityId.entityType; - rootEntityId = stateEntityId.id; - } else if (!result.stateEntity) { - rootEntityType = filter.rootEntity.entityType; - rootEntityId = filter.rootEntity.id; - } - if (rootEntityType && rootEntityId) { - const relationQueryRootEntityId = this.resolveAliasEntityId(rootEntityType, rootEntityId); - result.entityFilter = deepClone(filter); - result.entityFilter.rootEntity = relationQueryRootEntityId; - return of(result); - } else { - return of(result); - } case AliasFilterType.assetSearchQuery: case AliasFilterType.deviceSearchQuery: case AliasFilterType.edgeSearchQuery: case AliasFilterType.entityViewSearchQuery: + let rootEntityType; + let rootEntityId; result.stateEntity = filter.rootStateEntity; if (result.stateEntity && stateEntityId) { rootEntityType = stateEntityId.entityType; @@ -937,9 +921,9 @@ export class EntityService { rootEntityId = filter.rootEntity.id; } if (rootEntityType && rootEntityId) { - const searchQueryRootEntityId = this.resolveAliasEntityId(rootEntityType, rootEntityId); + const queryRootEntityId = this.resolveAliasEntityId(rootEntityType, rootEntityId); result.entityFilter = deepClone(filter); - result.entityFilter.rootEntity = searchQueryRootEntityId; + result.entityFilter.rootEntity = queryRootEntityId; return of(result); } else { return of(result); From c628957ec8f4084a0dc089015bd0af5963dca36d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 7 Dec 2021 18:44:58 +0200 Subject: [PATCH 292/303] Update ngx-flowchart --- ui-ngx/package.json | 2 +- .../home/pages/rulechain/rulechain-page.component.ts | 2 +- .../modules/home/pages/rulechain/rulechain-page.models.ts | 2 +- .../app/modules/home/pages/rulechain/rulechain.module.ts | 2 +- .../modules/home/pages/rulechain/rulenode.component.ts | 2 +- ui-ngx/src/app/shared/models/rule-node.models.ts | 2 +- ui-ngx/src/app/shared/shared.module.ts | 2 +- ui-ngx/yarn.lock | 8 ++++---- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 1256edc46c..adec5e815a 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -69,7 +69,7 @@ "ngx-color-picker": "^11.0.0", "ngx-daterangepicker-material": "^5.0.1", "ngx-drag-drop": "^2.0.0", - "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master", + "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#release/1.0.0", "ngx-hm-carousel": "^2.0.1", "ngx-markdown": "^12.0.1", "ngx-sharebuttons": "^9.0.0", diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index ea9cc54747..cc2c6c903d 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -50,7 +50,7 @@ import { RuleChainMetaData, ruleChainNodeComponent, RuleChainType } from '@shared/models/rule-chain.models'; -import { FcItemInfo, FlowchartConstants, NgxFlowchartComponent, UserCallbacks } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FcItemInfo, FlowchartConstants, NgxFlowchartComponent, UserCallbacks } from 'ngx-flowchart'; import { FcRuleEdge, FcRuleNode, diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.models.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.models.ts index b6ff534cf6..40a2f4cf28 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.models.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.models.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { FcModel } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FcModel } from 'ngx-flowchart'; import { FcRuleEdge, FcRuleNode, FcRuleNodeType } from '@shared/models/rule-node.models'; export interface FcRuleNodeTypeModel extends FcModel { diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts index 621149c7a8..95bb4bf3f8 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts @@ -27,7 +27,7 @@ import { RuleChainPageComponent } from './rulechain-page.component'; import { RuleNodeComponent } from '@home/pages/rulechain/rulenode.component'; -import { FC_NODE_COMPONENT_CONFIG } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FC_NODE_COMPONENT_CONFIG } from 'ngx-flowchart'; import { RuleNodeDetailsComponent } from './rule-node-details.component'; import { RuleNodeLinkComponent } from './rule-node-link.component'; import { LinkLabelsComponent } from '@home/pages/rulechain/link-labels.component'; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts index 03d5d17f55..ce7ff340d5 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts @@ -16,7 +16,7 @@ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { Component, OnInit } from '@angular/core'; -import { FcNodeComponent } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FcNodeComponent } from 'ngx-flowchart'; import { FcRuleNode, RuleNodeType } from '@shared/models/rule-node.models'; import { Router } from '@angular/router'; import { RuleChainType } from '@app/shared/models/rule-chain.models'; diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index 489c6eef10..097f8b2edc 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -18,7 +18,7 @@ import { BaseData } from '@shared/models/base-data'; import { RuleChainId } from '@shared/models/id/rule-chain-id'; import { RuleNodeId } from '@shared/models/id/rule-node-id'; import { ComponentDescriptor } from '@shared/models/component-descriptor.models'; -import { FcEdge, FcNode } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FcEdge, FcNode } from 'ngx-flowchart'; import { Observable } from 'rxjs'; import { PageComponent } from '@shared/components/page.component'; import { AfterViewInit, EventEmitter, Inject, OnInit, Directive } from '@angular/core'; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 50ffdafa65..1f66aedf47 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -21,7 +21,7 @@ import { LogoComponent } from '@shared/components/logo.component'; import { TbSnackBarComponent, ToastDirective } from '@shared/components/toast.directive'; import { BreadcrumbComponent } from '@shared/components/breadcrumb.component'; import { FlowInjectionToken, NgxFlowModule } from '@flowjs/ngx-flow'; -import { NgxFlowchartModule } from 'ngx-flowchart/dist/ngx-flowchart'; +import { NgxFlowchartModule } from 'ngx-flowchart'; import Flow from '@flowjs/flow.js'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index ba822f9116..f1e5a9abc9 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -6653,11 +6653,11 @@ ngx-drag-drop@^2.0.0: dependencies: tslib "^1.9.0" -"ngx-flowchart@git://github.com/thingsboard/ngx-flowchart.git#master": - version "0.0.0" - resolved "git://github.com/thingsboard/ngx-flowchart.git#078bfd2cedeeab412dee922e8066a19be6da7278" +"ngx-flowchart@git://github.com/thingsboard/ngx-flowchart.git#release/1.0.0": + version "0.0.1" + resolved "git://github.com/thingsboard/ngx-flowchart.git#aac96f7e0490a386d58864d7819873e7c63cbb48" dependencies: - tslib "^1.13.0" + tslib "^2.2.0" ngx-hm-carousel@^2.0.1: version "2.0.1" From d3c20b2e57494ab5fc828c797359da8d816c7148 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 7 Dec 2021 18:50:16 +0200 Subject: [PATCH 293/303] Alarm Query performance improvements --- .../main/data/upgrade/3.3.2/schema_update.sql | 29 ++++++ .../install/ThingsboardInstallService.java | 4 + .../install/SqlDatabaseUpgradeService.java | 22 +++++ .../server/common/data/alarm/EntityAlarm.java | 40 ++++++++ .../data/relation/RelationTypeGroup.java | 1 - .../server/dao/alarm/AlarmDao.java | 5 + .../server/dao/alarm/BaseAlarmService.java | 27 ++--- .../dao/entityview/EntityViewServiceImpl.java | 1 - .../server/dao/model/ModelConstants.java | 1 + .../model/sql/EntityAlarmCompositeKey.java | 42 ++++++++ .../dao/model/sql/EntityAlarmEntity.java | 99 +++++++++++++++++++ .../server/dao/sql/alarm/AlarmRepository.java | 55 ++++------- .../dao/sql/alarm/EntityAlarmRepository.java | 29 ++++++ .../server/dao/sql/alarm/JpaAlarmDao.java | 16 ++- .../query/DefaultAlarmQueryRepository.java | 21 ++-- .../sql/query/DefaultQueryLogComponent.java | 2 +- .../resources/sql/schema-entities-hsql.sql | 12 +++ .../resources/sql/schema-entities-idx.sql | 4 + .../main/resources/sql/schema-entities.sql | 12 +++ .../dao/service/BaseAlarmServiceTest.java | 19 ---- .../resources/sql/hsql/drop-all-tables.sql | 1 + .../resources/sql/psql/drop-all-tables.sql | 1 + .../sql/timescale/drop-all-tables.sql | 1 + 23 files changed, 366 insertions(+), 78 deletions(-) create mode 100644 application/src/main/data/upgrade/3.3.2/schema_update.sql create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmCompositeKey.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql new file mode 100644 index 0000000000..99d2294129 --- /dev/null +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -0,0 +1,29 @@ +-- +-- Copyright © 2016-2021 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. +-- + +CREATE TABLE IF NOT EXISTS entity_alarm ( + tenant_id uuid NOT NULL, + entity_id uuid NOT NULL, + created_time bigint NOT NULL, + type varchar(255) NOT NULL, + customer_id uuid, + alarm_id uuid + CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE +); + +CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); 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 ccdac8b363..5b1bee8538 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -210,6 +210,10 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 3.3.0 to 3.3.1 ..."); case "3.3.1": log.info("Upgrading ThingsBoard from version 3.3.1 to 3.3.2 ..."); + break; + case "3.3.2": + log.info("Upgrading ThingsBoard from version 3.3.2 to 3.3.3 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.3.2"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); 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 fcb9632020..3f9bec2d07 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 @@ -469,6 +469,28 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.3.2": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + try { + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" + + " select tenant_id, originator_id, created_time, type, customer_id, id, status, severity from alarm;"); + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" + + " select a.tenant_id, r.from_id, created_time, type, customer_id, id, status, severity" + + " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); + conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); + } catch (Exception e) { + log.error("Failed to update alarm relations!!!", e); + } + log.info("Updating schema settings..."); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); + log.info("Schema updated."); + } catch (Exception e) { + log.error("Failed updating schema!!!", e); + } + break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java new file mode 100644 index 0000000000..f6d4a0e2c7 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.alarm; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EntityAlarm implements HasTenantId { + + private TenantId tenantId; + private EntityId entityId; + private long createdTime; + private String alarmType; + + private CustomerId customerId; + private AlarmId alarmId; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java index c6ca10088d..c35a1dfd1a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java @@ -18,7 +18,6 @@ package org.thingsboard.server.common.data.relation; public enum RelationTypeGroup { COMMON, - ALARM, DASHBOARD, RULE_CHAIN, RULE_NODE, diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index 3b10f624d7..8918b7cc1f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.alarm.EntityAlarm; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; @@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.dao.Dao; import java.util.Collection; +import java.util.List; import java.util.Set; import java.util.UUID; @@ -59,4 +61,7 @@ public interface AlarmDao extends Dao { PageData findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); + void createEntityAlarmRecord(EntityAlarm entityAlarm); + + List findEntityAlarmRecords(TenantId tenantId, AlarmId id); } 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 90d988c20b..64874eff7d 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 @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.alarm.EntityAlarm; import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededException; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; @@ -166,23 +167,24 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private AlarmOperationResult createAlarm(Alarm alarm) throws InterruptedException, ExecutionException { log.debug("New Alarm : {}", alarm); Alarm saved = alarmDao.save(alarm.getTenantId(), alarm); - List propagatedEntitiesList = createAlarmRelations(saved); + List propagatedEntitiesList = createEntityAlarmRecords(saved); return new AlarmOperationResult(saved, true, true, propagatedEntitiesList); } - private List createAlarmRelations(Alarm alarm) throws InterruptedException, ExecutionException { + private List createEntityAlarmRecords(Alarm alarm) throws InterruptedException, ExecutionException { List propagatedEntitiesList; if (alarm.isPropagate()) { Set parentEntities = getParentEntities(alarm); propagatedEntitiesList = new ArrayList<>(parentEntities.size() + 1); for (EntityId parentId : parentEntities) { propagatedEntitiesList.add(parentId); - createAlarmRelation(alarm.getTenantId(), parentId, alarm.getId()); + createEntityAlarmRecord(alarm.getTenantId(), parentId, alarm); } propagatedEntitiesList.add(alarm.getOriginator()); } else { propagatedEntitiesList = Collections.singletonList(alarm.getOriginator()); } + createEntityAlarmRecord(alarm.getTenantId(), alarm.getOriginator(), alarm); return propagatedEntitiesList; } @@ -221,7 +223,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ List propagatedEntitiesList; if (!oldPropagate && newPropagate) { try { - propagatedEntitiesList = createAlarmRelations(result); + propagatedEntitiesList = createEntityAlarmRecords(result); } catch (InterruptedException | ExecutionException e) { log.warn("Failed to update alarm relations [{}]", result, e); throw new RuntimeException(e); @@ -382,17 +384,20 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private Set getPropagationEntityIds(Alarm alarm) { if (alarm.isPropagate()) { - List relations = relationService.findByTo(alarm.getTenantId(), alarm.getId(), RelationTypeGroup.ALARM); - Set propagationEntityIds = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet()); - propagationEntityIds.add(alarm.getOriginator()); - return propagationEntityIds; + List entityAlarms = alarmDao.findEntityAlarmRecords(alarm.getTenantId(), alarm.getId()); + return entityAlarms.stream().map(EntityAlarm::getEntityId).collect(Collectors.toSet()); } else { return Collections.singleton(alarm.getOriginator()); } } - private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId) { - createRelation(tenantId, new EntityRelation(entityId, alarmId, AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM)); + private void createEntityAlarmRecord(TenantId tenantId, EntityId entityId, Alarm alarm) { + EntityAlarm entityAlarm = new EntityAlarm(tenantId, entityId, alarm.getCreatedTime(), alarm.getType(), alarm.getCustomerId(), alarm.getId()); + try { + alarmDao.createEntityAlarmRecord(entityAlarm); + } catch (Exception e) { + log.warn("[{}] Failed to create entity alarm record: {}", tenantId, entityAlarm, e); + } } private ListenableFuture getAndUpdate(TenantId tenantId, AlarmId alarmId, Function function) { @@ -402,7 +407,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } private DataValidator alarmDataValidator = - new DataValidator() { + new DataValidator<>() { @Override protected void validateDataImpl(TenantId tenantId, Alarm alarm) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 304b04a33d..33ea3d635f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -44,7 +44,6 @@ import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationTypeGroup; 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 e8e90f2d3c..6f7a3c2567 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 @@ -257,6 +257,7 @@ public class ModelConstants { /** * Cassandra alarm constants. */ + public static final String ENTITY_ALARM_COLUMN_FAMILY_NAME = "entity_alarm"; public static final String ALARM_COLUMN_FAMILY_NAME = "alarm"; public static final String ALARM_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String ALARM_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmCompositeKey.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmCompositeKey.java new file mode 100644 index 0000000000..69152418b8 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmCompositeKey.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.model.sql; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.alarm.EntityAlarm; + +import javax.persistence.Transient; +import java.io.Serializable; +import java.util.UUID; + +@NoArgsConstructor +@AllArgsConstructor +@Data +public class EntityAlarmCompositeKey implements Serializable { + + @Transient + private static final long serialVersionUID = -245388185894468450L; + + private UUID entityId; + private UUID alarmId; + + public EntityAlarmCompositeKey(EntityAlarm entityAlarm) { + this.entityId = entityAlarm.getEntityId().getId(); + this.alarmId = entityAlarm.getAlarmId().getId(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java new file mode 100644 index 0000000000..50d57cf61c --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java @@ -0,0 +1,99 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.model.sql; + +import lombok.Data; +import org.thingsboard.server.common.data.alarm.EntityAlarm; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.model.ToData; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.Table; +import java.util.UUID; + +import static org.thingsboard.server.dao.model.ModelConstants.CREATED_TIME_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ALARM_COLUMN_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_COLUMN; +import static org.thingsboard.server.dao.model.ModelConstants.TENANT_ID_COLUMN; + +@Data +@Entity +@Table(name = ENTITY_ALARM_COLUMN_FAMILY_NAME) +@IdClass(EntityAlarmCompositeKey.class) +public final class EntityAlarmEntity implements ToData { + + @Column(name = TENANT_ID_COLUMN, columnDefinition = "uuid") + private UUID tenantId; + + @Column(name = ENTITY_TYPE_COLUMN) + private String entityType; + + @Id + @Column(name = ENTITY_ID_COLUMN, columnDefinition = "uuid") + private UUID entityId; + + @Id + @Column(name = "alarm_id", columnDefinition = "uuid") + private UUID alarmId; + + @Column(name = CREATED_TIME_PROPERTY) + private long createdTime; + + @Column(name = "alarm_type") + private String alarmType; + + @Column(name = CUSTOMER_ID_PROPERTY, columnDefinition = "uuid") + private UUID customerId; + + public EntityAlarmEntity() { + super(); + } + + public EntityAlarmEntity(EntityAlarm entityAlarm) { + tenantId = entityAlarm.getTenantId().getId(); + entityId = entityAlarm.getEntityId().getId(); + entityType = entityAlarm.getEntityId().getEntityType().name(); + alarmId = entityAlarm.getAlarmId().getId(); + alarmType = entityAlarm.getAlarmType(); + createdTime = entityAlarm.getCreatedTime(); + if (entityAlarm.getCustomerId() != null) { + customerId = entityAlarm.getCustomerId().getId(); + } + } + + @Override + public EntityAlarm toData() { + EntityAlarm result = new EntityAlarm(); + result.setTenantId(new TenantId(tenantId)); + result.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId)); + result.setAlarmId(new AlarmId(alarmId)); + result.setAlarmType(alarmType); + result.setCreatedTime(createdTime); + if (customerId != null) { + result.setCustomerId(new CustomerId(customerId)); + } + return result; + } + +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index a67e29bac0..0152ef058d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -42,47 +42,28 @@ public interface AlarmRepository extends CrudRepository { Pageable pageable); @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + - "LEFT JOIN RelationEntity re ON a.id = re.toId " + - "AND re.relationTypeGroup = 'ALARM' " + - "AND re.toType = 'ALARM' " + - "AND re.fromId = :affectedEntityId " + - "AND re.fromType = :affectedEntityType " + + "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " + "WHERE a.tenantId = :tenantId " + - "AND (a.originatorId = :affectedEntityId or re.fromId IS NOT NULL) " + - "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + - "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + + "AND ea.tenantId = :tenantId " + + "AND ea.entityId = :affectedEntityId " + + "AND ea.entityType = :affectedEntityType " + + "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " , countQuery = "" + - "SELECT count(a) + " + //alarms with relations only - " (SELECT count(a) FROM AlarmEntity a " + //alarms WITHOUT any relations - " LEFT JOIN RelationEntity re ON a.id = re.toId " + - " AND re.relationTypeGroup = 'ALARM' " + - " AND re.toType = 'ALARM' " + - " AND re.fromId = :affectedEntityId " + - " AND re.fromType = :affectedEntityType " + - " WHERE a.tenantId = :tenantId " + - " AND (a.originatorId = :affectedEntityId) " + - " AND (re.fromId IS NULL) " + //anti join - " AND (:startTime IS NULL OR a.createdTime >= :startTime) " + - " AND (:endTime IS NULL OR a.createdTime <= :endTime) " + - " AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - " AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " + - " )" + + "SELECT count(a) " + //alarms with relations only "FROM AlarmEntity a " + - "INNER JOIN RelationEntity re ON a.id = re.toId " + - "AND re.relationTypeGroup = 'ALARM' " + - "AND re.toType = 'ALARM' " + - "AND re.fromId = :affectedEntityId " + - "AND re.fromType = :affectedEntityType " + + "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " + "WHERE a.tenantId = :tenantId " + - "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + - "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + + "AND ea.tenantId = :tenantId " + + "AND ea.entityId = :affectedEntityId " + + "AND ea.entityType = :affectedEntityType " + + "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + @@ -149,13 +130,11 @@ public interface AlarmRepository extends CrudRepository { Pageable pageable); @Query(value = "SELECT a.severity FROM AlarmEntity a " + - "LEFT JOIN RelationEntity re ON a.id = re.toId " + - "AND re.relationTypeGroup = 'ALARM' " + - "AND re.toType = 'ALARM' " + - "AND re.fromId = :affectedEntityId " + - "AND re.fromType = :affectedEntityType " + + "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " + "WHERE a.tenantId = :tenantId " + - "AND (a.originatorId = :affectedEntityId or re.fromId IS NOT NULL) " + + "AND ea.tenantId = :tenantId " + + "AND ea.entityId = :affectedEntityId " + + "AND ea.entityType = :affectedEntityType " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses))") Set findAlarmSeverities(@Param("tenantId") UUID tenantId, @Param("affectedEntityId") UUID affectedEntityId, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java new file mode 100644 index 0000000000..ad67e9ba1d --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.sql.alarm; + +import org.springframework.data.repository.CrudRepository; +import org.thingsboard.server.dao.model.sql.EntityAlarmCompositeKey; +import org.thingsboard.server.dao.model.sql.EntityAlarmEntity; + +import java.util.List; +import java.util.UUID; + +public interface EntityAlarmRepository extends CrudRepository { + + List findAllByAlarmId(UUID alarmId); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index 3216a23eee..73e7a39b9a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.alarm.EntityAlarm; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; @@ -37,6 +38,7 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.alarm.AlarmDao; import org.thingsboard.server.dao.model.sql.AlarmEntity; +import org.thingsboard.server.dao.model.sql.EntityAlarmEntity; import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.sql.query.AlarmQueryRepository; @@ -62,7 +64,7 @@ public class JpaAlarmDao extends JpaAbstractDao implements A private AlarmQueryRepository alarmQueryRepository; @Autowired - private RelationDao relationDao; + private EntityAlarmRepository entityAlarmRepository; @Override protected Class getEntityClass() { @@ -169,4 +171,16 @@ public class JpaAlarmDao extends JpaAbstractDao implements A return DaoUtil.pageToPageData(alarmRepository.findAlarmsIdsByEndTsBeforeAndTenantId(time, tenantId.getId(), DaoUtil.toPageable(pageLink))) .mapData(AlarmId::new); } + + @Override + public void createEntityAlarmRecord(EntityAlarm entityAlarm) { + log.debug("Saving entity {}", entityAlarm); + entityAlarmRepository.save(new EntityAlarmEntity(entityAlarm)); + } + + @Override + public List findEntityAlarmRecords(TenantId tenantId, AlarmId id) { + log.trace("[{}] Try to find entity alarm records using [{}]", tenantId, id); + return DaoUtil.convertDataList(entityAlarmRepository.findAllByAlarmId(id.getId())); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java index 400b12fcab..3fee0f6bef 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java @@ -105,7 +105,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { " a.propagate_relation_types as propagate_relation_types, " + " a.type as type," + SELECT_ORIGINATOR_NAME + ", "; - private static final String JOIN_RELATIONS = "left join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id and r.from_id in (:entity_ids)"; + private static final String JOIN_ENTITY_ALARMS = "inner join entity_alarm ea on a.id = ea.alarm_id"; protected final NamedParameterJdbcTemplate jdbcTemplate; private final TransactionTemplate transactionTemplate; @@ -132,8 +132,8 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { StringBuilder joinPart = new StringBuilder(); boolean addAnd = false; if (pageLink.isSearchPropagatedAlarms()) { - selectPart.append(" CASE WHEN r.from_id IS NULL THEN a.originator_id ELSE r.from_id END as entity_id "); - fromPart.append(JOIN_RELATIONS); + selectPart.append(" ea.entity_id as entity_id "); + fromPart.append(JOIN_ENTITY_ALARMS); wherePart.append(buildPermissionsQuery(tenantId, customerId, ctx)); addAnd = true; } else { @@ -145,7 +145,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { sortPart.append(alarmFieldColumnMap.getOrDefault(sortOrderKey, sortOrderKey)) .append(" ").append(sortOrder.getDirection().name()); if (pageLink.isSearchPropagatedAlarms()) { - wherePart.append(" and (a.originator_id in (:entity_ids) or r.from_id IS NOT NULL)"); + wherePart.append(" and ea.entity_id in (:entity_ids)"); } else { addAndIfNeeded(wherePart, addAnd); addAnd = true; @@ -166,7 +166,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { } joinPart.append(" as e(id, priority)) e "); if (pageLink.isSearchPropagatedAlarms()) { - joinPart.append("on (r.from_id IS NULL and a.originator_id = e.id) or (r.from_id IS NOT NULL and r.from_id = e.id)"); + joinPart.append("on ea.entity_id = e.id"); } else { joinPart.append("on a.originator_id = e.id"); } @@ -188,6 +188,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { addAnd = true; ctx.addLongParameter("startTime", startTs); wherePart.append("a.created_time >= :startTime"); + if (pageLink.isSearchPropagatedAlarms()) { + wherePart.append(" and ea.created_time >= :startTime"); + } } if (endTs > 0) { @@ -195,6 +198,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { addAnd = true; ctx.addLongParameter("endTime", endTs); wherePart.append("a.created_time <= :endTime"); + if (pageLink.isSearchPropagatedAlarms()) { + wherePart.append(" and ea.created_time <= :endTime"); + } } if (pageLink.getTypeList() != null && !pageLink.getTypeList().isEmpty()) { @@ -202,6 +208,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { addAnd = true; ctx.addStringListParameter("alarmTypes", pageLink.getTypeList()); wherePart.append("a.type in (:alarmTypes)"); + if (pageLink.isSearchPropagatedAlarms()) { + wherePart.append(" and ea.alarm_type in (:alarmTypes)"); + } } if (pageLink.getSeverityList() != null && !pageLink.getSeverityList().isEmpty()) { @@ -279,7 +288,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { private String buildPermissionsQuery(TenantId tenantId, CustomerId customerId, QueryContext ctx) { StringBuilder permissionsQuery = new StringBuilder(); ctx.addUuidParameter("permissions_tenant_id", tenantId.getId()); - permissionsQuery.append(" a.tenant_id = :permissions_tenant_id "); + permissionsQuery.append(" a.tenant_id = :permissions_tenant_id and ea.tenant_id = :permissions_tenant_id "); /* No need to check the customer id, because we already use entity id list that passed security check when we were evaluating the data query. */ diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultQueryLogComponent.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultQueryLogComponent.java index 89bf4d1ac1..737c148d49 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultQueryLogComponent.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultQueryLogComponent.java @@ -33,7 +33,7 @@ public class DefaultQueryLogComponent implements QueryLogComponent { @Override public void logQuery(QueryContext ctx, String query, long duration) { if (logSqlQueries && duration > logQueriesThreshold) { - log.info("QUERY: {} took {}ms", query, duration); + log.info("QUERY: {} took {} ms", query, duration); Arrays.asList(ctx.getParameterNames()).forEach(param -> log.info("QUERY PARAM: {} -> {}", param, ctx.getValue(param))); } } diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql index e58ca10459..c5931a8964 100644 --- a/dao/src/main/resources/sql/schema-entities-hsql.sql +++ b/dao/src/main/resources/sql/schema-entities-hsql.sql @@ -43,6 +43,18 @@ CREATE TABLE IF NOT EXISTS alarm ( type varchar(255) ); +CREATE TABLE IF NOT EXISTS entity_alarm ( + tenant_id uuid NOT NULL, + entity_type varchar(32), + entity_id uuid NOT NULL, + created_time bigint NOT NULL, + alarm_type varchar(255) NOT NULL, + customer_id uuid, + alarm_id uuid, + CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE +); + CREATE TABLE IF NOT EXISTS asset ( id uuid NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, created_time bigint NOT NULL, diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index 78b1eda905..1238b5ee12 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -20,8 +20,12 @@ CREATE INDEX IF NOT EXISTS idx_alarm_originator_created_time ON alarm(originator CREATE INDEX IF NOT EXISTS idx_alarm_tenant_created_time ON alarm(tenant_id, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC); + CREATE INDEX IF NOT EXISTS idx_alarm_tenant_alarm_type_created_time ON alarm(tenant_id, type, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); + CREATE INDEX IF NOT EXISTS idx_relation_to_id ON relation(relation_type_group, to_type, to_id); CREATE INDEX IF NOT EXISTS idx_relation_from_id ON relation(relation_type_group, from_type, from_id); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 69760c377a..de27c8d554 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -58,6 +58,18 @@ CREATE TABLE IF NOT EXISTS alarm ( type varchar(255) ); +CREATE TABLE IF NOT EXISTS entity_alarm ( + tenant_id uuid NOT NULL, + entity_type varchar(32), + entity_id uuid NOT NULL, + created_time bigint NOT NULL, + alarm_type varchar(255) NOT NULL, + customer_id uuid, + alarm_id uuid, + CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE +); + CREATE TABLE IF NOT EXISTS asset ( id uuid NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, created_time bigint NOT NULL, diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index a798133ad4..2d3f21545f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -612,16 +612,6 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { Assert.assertEquals(1, alarms.getData().size()); Assert.assertEquals(created, alarms.getData().get(0)); - List toAlarmRelations = relationService.findByTo(tenantId, created.getId(), RelationTypeGroup.ALARM); - Assert.assertEquals(1, toAlarmRelations.size()); - - List fromChildRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM); - Assert.assertEquals(0, fromChildRelations.size()); - - List fromParentRelations = relationService.findByFrom(tenantId, parentId, RelationTypeGroup.ALARM); - Assert.assertEquals(1, fromParentRelations.size()); - - Assert.assertTrue("Alarm was not deleted when expected", alarmService.deleteAlarm(tenantId, created.getId()).isSuccessful()); Alarm fetched = alarmService.findAlarmByIdAsync(tenantId, created.getId()).get(); @@ -647,14 +637,5 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { Assert.assertNotNull(alarms.getData()); Assert.assertEquals(0, alarms.getData().size()); - toAlarmRelations = relationService.findByTo(tenantId, created.getId(), RelationTypeGroup.ALARM); - Assert.assertEquals(0, toAlarmRelations.size()); - - fromChildRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM); - Assert.assertEquals(0, fromChildRelations.size()); - - fromParentRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM); - Assert.assertEquals(0, fromParentRelations.size()); - } } diff --git a/dao/src/test/resources/sql/hsql/drop-all-tables.sql b/dao/src/test/resources/sql/hsql/drop-all-tables.sql index 2cd7e26b48..095a38533e 100644 --- a/dao/src/test/resources/sql/hsql/drop-all-tables.sql +++ b/dao/src/test/resources/sql/hsql/drop-all-tables.sql @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS admin_settings; +DROP TABLE IF EXISTS entity_alarm; DROP TABLE IF EXISTS alarm; DROP TABLE IF EXISTS asset; DROP TABLE IF EXISTS audit_log; diff --git a/dao/src/test/resources/sql/psql/drop-all-tables.sql b/dao/src/test/resources/sql/psql/drop-all-tables.sql index 0a71953032..3d1d38a0e7 100644 --- a/dao/src/test/resources/sql/psql/drop-all-tables.sql +++ b/dao/src/test/resources/sql/psql/drop-all-tables.sql @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS admin_settings; +DROP TABLE IF EXISTS entity_alarm; DROP TABLE IF EXISTS alarm; DROP TABLE IF EXISTS asset; DROP TABLE IF EXISTS audit_log; diff --git a/dao/src/test/resources/sql/timescale/drop-all-tables.sql b/dao/src/test/resources/sql/timescale/drop-all-tables.sql index 53da64aff2..f113ec5277 100644 --- a/dao/src/test/resources/sql/timescale/drop-all-tables.sql +++ b/dao/src/test/resources/sql/timescale/drop-all-tables.sql @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS admin_settings; +DROP TABLE IF EXISTS entity_alarm; DROP TABLE IF EXISTS alarm; DROP TABLE IF EXISTS asset; DROP TABLE IF EXISTS audit_log; From d6e18d05cd46d1ad407979878009446b66d42696 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 8 Dec 2021 15:35:59 +0200 Subject: [PATCH 294/303] Introduce Flow rule node type. Add rile node UIs for RuleChain input/output. Remove rule chain connection metadata. --- .../AnnotationComponentDiscoveryService.java | 27 ++-- .../common/data/plugin/ComponentType.java | 2 +- .../rule/engine/api/NodeDefinition.java | 1 + .../thingsboard/rule/engine/api/RuleNode.java | 2 + .../rule/engine/flow/TbAckNode.java | 2 +- .../rule/engine/flow/TbCheckpointNode.java | 2 +- .../engine/flow/TbRuleChainInputNode.java | 8 +- .../engine/flow/TbRuleChainOutputNode.java | 6 +- .../static/rulenode/rulenode-core-config.js | 96 +++++++++++- .../src/app/core/http/rule-chain.service.ts | 83 ++-------- .../import-export/import-export.service.ts | 9 +- .../home/pages/edge/edge-routing.module.ts | 8 +- .../add-rule-node-link-dialog.component.html | 3 +- .../pages/rulechain/link-labels.component.ts | 74 ++++++--- .../pages/rulechain/rule-node-colors.scss | 2 +- .../rulechain/rule-node-config.component.ts | 9 ++ .../rule-node-details.component.html | 20 +-- .../rulechain/rule-node-details.component.ts | 62 ++------ .../rulechain/rule-node-link.component.html | 1 + .../rulechain/rule-node-link.component.ts | 3 + .../rulechain/rulechain-page.component.html | 3 +- .../rulechain/rulechain-page.component.scss | 2 +- .../rulechain/rulechain-page.component.ts | 147 +++++------------- .../rulechain/rulechain-routing.module.ts | 12 +- .../pages/rulechain/rulenode.component.html | 4 +- .../pages/rulechain/rulenode.component.ts | 43 ++++- .../models/component-descriptor.models.ts | 3 +- .../app/shared/models/rule-chain.models.ts | 33 +--- .../src/app/shared/models/rule-node.models.ts | 23 ++- .../assets/locale/locale.constant-en_US.json | 2 + 30 files changed, 339 insertions(+), 353 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index 00a5bca503..eaacde0874 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -152,24 +152,14 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe try { scannedComponent.setType(type); Class clazz = Class.forName(clazzName); - switch (type) { - case ENRICHMENT: - case FILTER: - case TRANSFORMATION: - case ACTION: - case EXTERNAL: - RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); - scannedComponent.setName(ruleNodeAnnotation.name()); - scannedComponent.setScope(ruleNodeAnnotation.scope()); - NodeDefinition nodeDefinition = prepareNodeDefinition(ruleNodeAnnotation); - ObjectNode configurationDescriptor = mapper.createObjectNode(); - JsonNode node = mapper.valueToTree(nodeDefinition); - configurationDescriptor.set("nodeDefinition", node); - scannedComponent.setConfigurationDescriptor(configurationDescriptor); - break; - default: - throw new RuntimeException(type + " is not supported yet!"); - } + RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); + scannedComponent.setName(ruleNodeAnnotation.name()); + scannedComponent.setScope(ruleNodeAnnotation.scope()); + NodeDefinition nodeDefinition = prepareNodeDefinition(ruleNodeAnnotation); + ObjectNode configurationDescriptor = mapper.createObjectNode(); + JsonNode node = mapper.valueToTree(nodeDefinition); + configurationDescriptor.set("nodeDefinition", node); + scannedComponent.setConfigurationDescriptor(configurationDescriptor); scannedComponent.setClazz(clazzName); log.info("Processing scanned component: {}", scannedComponent); } catch (Exception e) { @@ -200,6 +190,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled()); nodeDefinition.setRelationTypes(getRelationTypesWithFailureRelation(nodeAnnotation)); nodeDefinition.setCustomRelations(nodeAnnotation.customRelations()); + nodeDefinition.setRuleChainNode(nodeAnnotation.ruleChainNode()); Class configClazz = nodeAnnotation.configClazz(); NodeConfiguration config = configClazz.getDeclaredConstructor().newInstance(); NodeConfiguration defaultConfiguration = config.defaultConfiguration(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java index 26c61a03bf..cdb45538ea 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java @@ -20,6 +20,6 @@ package org.thingsboard.server.common.data.plugin; */ public enum ComponentType { - ENRICHMENT, FILTER, TRANSFORMATION, ACTION, EXTERNAL + ENRICHMENT, FILTER, TRANSFORMATION, ACTION, EXTERNAL, FLOW } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java index 531ac61a2c..5933b1bf18 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java @@ -27,6 +27,7 @@ public class NodeDefinition { private boolean outEnabled; String[] relationTypes; boolean customRelations; + boolean ruleChainNode; JsonNode defaultConfiguration; String[] uiResources; String configDirective; diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java index 53b52491da..7a0f99e2d0 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java @@ -58,6 +58,8 @@ public @interface RuleNode { boolean customRelations() default false; + boolean ruleChainNode() default false; + RuleChainType[] ruleChainTypes() default {RuleChainType.CORE, RuleChainType.EDGE}; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java index e10a20232d..850eed19bf 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java @@ -28,7 +28,7 @@ import org.thingsboard.server.common.msg.TbMsg; @Slf4j @RuleNode( - type = ComponentType.ACTION, + type = ComponentType.FLOW, name = "acknowledge", configClazz = EmptyNodeConfiguration.class, nodeDescription = "Acknowledges the incoming message", diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java index cc3944452a..4f3bc327ec 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java @@ -31,7 +31,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; @Slf4j @RuleNode( - type = ComponentType.ACTION, + type = ComponentType.FLOW, name = "checkpoint", configClazz = TbCheckpointNodeConfiguration.class, nodeDescription = "transfers the message to another queue", diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java index c30dac406c..a1e1e31954 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java @@ -33,14 +33,18 @@ import java.util.UUID; @Slf4j @RuleNode( - type = ComponentType.ACTION, - name = "rule chain input", + type = ComponentType.FLOW, + name = "rule chain", configClazz = TbRuleChainInputNodeConfiguration.class, nodeDescription = "transfers the message to another rule chain", nodeDetails = "Allows to nest the rule chain similar to single rule node. " + "The incoming message is forwarded to the input node of the specified target rule chain. " + "The target rule chain may produce multiple labeled outputs. " + "You may use the outputs to forward the results of processing to other rule nodes.", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbFlowNodeRuleChainInputConfig", + relationTypes = {}, + ruleChainNode = true, customRelations = true ) public class TbRuleChainInputNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java index b09f1bbca5..f5f75f1275 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java @@ -28,14 +28,16 @@ import org.thingsboard.server.common.msg.TbMsg; @Slf4j @RuleNode( - type = ComponentType.ACTION, - name = "rule chain output", + type = ComponentType.FLOW, + name = "output", configClazz = TbRuleChainOutputNodeConfiguration.class, nodeDescription = "transfers the message to the caller rule chain", nodeDetails = "Produces output of the rule chain processing. " + "The output is forwarded to the caller rule chain, as an output of the corresponding \"input\" rule node. " + "The rule node configuration contains the \"label\" parameter. " + "This parameter corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbFlowNodeRuleChainOutputConfig", outEnabled = false ) public class TbRuleChainOutputNode implements TbNode { 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 8236c14be8..702fdabe6f 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 @@ -3691,6 +3691,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImpo }] }] }); +class RuleChainInputComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.entityType = EntityType; + } + configForm() { + return this.ruleChainInputConfigForm; + } + onConfigurationSet(configuration) { + this.ruleChainInputConfigForm = this.fb.group({ + ruleChainId: [configuration ? configuration.ruleChainId : null, [Validators.required]] + }); + } +} +RuleChainInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainInputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RuleChainInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainInputComponent, selector: "tb-flow-node-rule-chain-input-config", usesInheritance: true, ngImport: i0, template: "
        \n \n \n
        \n", components: [{ type: i8$3.EntityAutocompleteComponent, selector: "tb-entity-autocomplete", inputs: ["entityType", "entitySubtype", "excludeEntityIds", "labelText", "requiredText", "required", "disabled"], outputs: ["entityChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainInputComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-flow-node-rule-chain-input-config', + templateUrl: './rule-chain-input.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RuleChainOutputComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.ruleChainOutputConfigForm; + } + onConfigurationSet(configuration) { + this.ruleChainOutputConfigForm = this.fb.group({ + label: [configuration ? configuration.label : null, [Validators.required]] + }); + } +} +RuleChainOutputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.label\n \n \n {{ 'tb.rulenode.label-required' | translate }}\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-flow-node-rule-chain-output-config', + templateUrl: './rule-chain-output.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RuleNodeCoreConfigFlowModule { +} +RuleNodeCoreConfigFlowModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RuleNodeCoreConfigFlowModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, declarations: [RuleChainInputComponent, + RuleChainOutputComponent], imports: [CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule], exports: [RuleChainInputComponent, + RuleChainOutputComponent] }); +RuleNodeCoreConfigFlowModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, imports: [[ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + RuleChainInputComponent, + RuleChainOutputComponent + ], + imports: [ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + RuleChainInputComponent, + RuleChainOutputComponent + ] + }] + }] }); + function addRuleNodeCoreLocaleEnglish(translate) { const enUS = { tb: { @@ -4105,7 +4190,9 @@ function addRuleNodeCoreLocaleEnglish(translate) { 'for value from message body', 'alarm-severity-pattern-hint': 'Hint: use ${metadataKey} ' + 'for value from metadata, $[messageKey] ' + - 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)' + 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)', + label: 'Label', + 'label-required': 'Label is required' }, 'key-val': { key: 'Key', @@ -4134,6 +4221,7 @@ RuleNodeCoreConfigModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0" RuleNodeCoreConfigFilterModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, + RuleNodeCoreConfigFlowModule, EmptyConfigComponent] }); RuleNodeCoreConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, imports: [[ CommonModule, @@ -4141,7 +4229,8 @@ RuleNodeCoreConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0" ], RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RulenodeCoreConfigEnrichmentModule, - RulenodeCoreConfigTransformModule] }); + RulenodeCoreConfigTransformModule, + RuleNodeCoreConfigFlowModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, decorators: [{ type: NgModule, args: [{ @@ -4157,6 +4246,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImpo RuleNodeCoreConfigFilterModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, + RuleNodeCoreConfigFlowModule, EmptyConfigComponent ] }] @@ -4170,5 +4260,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImpo * Generated bundle index. Do not edit. */ -export { AssignCustomerConfigComponent, AttributesConfigComponent, AzureIotHubConfigComponent, CalculateDeltaConfigComponent, ChangeOriginatorConfigComponent, CheckAlarmStatusComponent, CheckMessageConfigComponent, CheckPointConfigComponent, CheckRelationConfigComponent, ClearAlarmConfigComponent, CreateAlarmConfigComponent, CreateRelationConfigComponent, CredentialsConfigComponent, CustomerAttributesConfigComponent, DeleteRelationConfigComponent, DeviceAttributesConfigComponent, DeviceProfileConfigComponent, DeviceRelationsQueryConfigComponent, EmptyConfigComponent, EntityDetailsConfigComponent, GeneratorConfigComponent, GetTelemetryFromDatabaseConfigComponent, GpsGeoActionConfigComponent, GpsGeoFilterConfigComponent, KafkaConfigComponent, KvMapConfigComponent, LogConfigComponent, MessageTypeConfigComponent, MessageTypesConfigComponent, MqttConfigComponent, MsgCountConfigComponent, MsgDelayConfigComponent, OriginatorAttributesConfigComponent, OriginatorFieldsConfigComponent, OriginatorTypeConfigComponent, PubSubConfigComponent, PushToCloudConfigComponent, PushToEdgeConfigComponent, RabbitMqConfigComponent, RelatedAttributesConfigComponent, RelationsQueryConfigComponent, RestApiCallConfigComponent, RpcReplyConfigComponent, RpcRequestConfigComponent, RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RuleNodeCoreConfigModule, RulenodeCoreConfigCommonModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, SafeHtmlPipe, SaveToCustomTableConfigComponent, ScriptConfigComponent, SendEmailConfigComponent, SendSmsConfigComponent, SnsConfigComponent, SqsConfigComponent, SwitchConfigComponent, TenantAttributesConfigComponent, TimeseriesConfigComponent, ToEmailConfigComponent, TransformScriptConfigComponent, UnassignCustomerConfigComponent }; +export { AssignCustomerConfigComponent, AttributesConfigComponent, AzureIotHubConfigComponent, CalculateDeltaConfigComponent, ChangeOriginatorConfigComponent, CheckAlarmStatusComponent, CheckMessageConfigComponent, CheckPointConfigComponent, CheckRelationConfigComponent, ClearAlarmConfigComponent, CreateAlarmConfigComponent, CreateRelationConfigComponent, CredentialsConfigComponent, CustomerAttributesConfigComponent, DeleteRelationConfigComponent, DeviceAttributesConfigComponent, DeviceProfileConfigComponent, DeviceRelationsQueryConfigComponent, EmptyConfigComponent, EntityDetailsConfigComponent, GeneratorConfigComponent, GetTelemetryFromDatabaseConfigComponent, GpsGeoActionConfigComponent, GpsGeoFilterConfigComponent, KafkaConfigComponent, KvMapConfigComponent, LogConfigComponent, MessageTypeConfigComponent, MessageTypesConfigComponent, MqttConfigComponent, MsgCountConfigComponent, MsgDelayConfigComponent, OriginatorAttributesConfigComponent, OriginatorFieldsConfigComponent, OriginatorTypeConfigComponent, PubSubConfigComponent, PushToCloudConfigComponent, PushToEdgeConfigComponent, RabbitMqConfigComponent, RelatedAttributesConfigComponent, RelationsQueryConfigComponent, RestApiCallConfigComponent, RpcReplyConfigComponent, RpcRequestConfigComponent, RuleChainInputComponent, RuleChainOutputComponent, RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RuleNodeCoreConfigFlowModule, RuleNodeCoreConfigModule, RulenodeCoreConfigCommonModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, SafeHtmlPipe, SaveToCustomTableConfigComponent, ScriptConfigComponent, SendEmailConfigComponent, SendSmsConfigComponent, SnsConfigComponent, SqsConfigComponent, SwitchConfigComponent, TenantAttributesConfigComponent, TimeseriesConfigComponent, ToEmailConfigComponent, TransformScriptConfigComponent, UnassignCustomerConfigComponent }; //# sourceMappingURL=rulenode-core-config.js.map diff --git a/ui-ngx/src/app/core/http/rule-chain.service.ts b/ui-ngx/src/app/core/http/rule-chain.service.ts index 0e11c51fcb..3fa9168d5f 100644 --- a/ui-ngx/src/app/core/http/rule-chain.service.ts +++ b/ui-ngx/src/app/core/http/rule-chain.service.ts @@ -21,11 +21,8 @@ import { HttpClient } from '@angular/common/http'; import { PageLink } from '@shared/models/page/page-link'; import { PageData } from '@shared/models/page/page-data'; import { - ResolvedRuleChainMetaData, RuleChain, - RuleChainConnectionInfo, RuleChainMetaData, - ruleChainNodeComponent, RuleChainType, ruleNodeTypeComponentTypes, unknownNodeComponent @@ -34,14 +31,13 @@ import { ComponentDescriptorService } from './component-descriptor.service'; import { IRuleNodeConfigurationComponent, LinkLabel, - RuleNodeComponentDescriptor, + RuleNodeComponentDescriptor, RuleNodeConfiguration, TestScriptInputParams, TestScriptResult } from '@app/shared/models/rule-node.models'; import { ResourcesService } from '../services/resources.service'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; -import { EntityType } from '@shared/models/entity-type.models'; import { deepClone, snakeCase } from '@core/utils'; import { DebugRuleNodeEventBody } from '@app/shared/models/event.models'; import { Edge } from '@shared/models/edge.models'; @@ -63,7 +59,8 @@ export class RuleChainService { private translate: TranslateService ) { } - public getRuleChains(pageLink: PageLink, type: RuleChainType = RuleChainType.CORE, config?: RequestConfig): Observable> { + public getRuleChains(pageLink: PageLink, type: RuleChainType = RuleChainType.CORE, + config?: RequestConfig): Observable> { return this.http.get>(`/api/ruleChains${pageLink.toQuery()}&type=${type}`, defaultHttpOptionsFromConfig(config)); } @@ -72,6 +69,10 @@ export class RuleChainService { return this.http.get(`/api/ruleChain/${ruleChainId}`, defaultHttpOptionsFromConfig(config)); } + public getRuleChainOutputLabels(ruleChainId: string, config?: RequestConfig): Observable> { + return this.http.get>(`/api/ruleChain/${ruleChainId}/output/labels`, defaultHttpOptionsFromConfig(config)); + } + public createDefaultRuleChain(ruleChainName: string, config?: RequestConfig): Observable { return this.http.post('/api/ruleChain/device/default', { name: ruleChainName @@ -94,32 +95,10 @@ export class RuleChainService { return this.http.get(`/api/ruleChain/${ruleChainId}/metadata`, defaultHttpOptionsFromConfig(config)); } - public getResolvedRuleChainMetadata(ruleChainId: string, config?: RequestConfig): Observable { - return this.getRuleChainMetadata(ruleChainId, config).pipe( - mergeMap((ruleChainMetaData) => this.resolveRuleChainMetadata(ruleChainMetaData)) - ); - } - public saveRuleChainMetadata(ruleChainMetaData: RuleChainMetaData, config?: RequestConfig): Observable { return this.http.post('/api/ruleChain/metadata', ruleChainMetaData, defaultHttpOptionsFromConfig(config)); } - public saveAndGetResolvedRuleChainMetadata(ruleChainMetaData: RuleChainMetaData, - config?: RequestConfig): Observable { - return this.saveRuleChainMetadata(ruleChainMetaData, config).pipe( - mergeMap((savedRuleChainMetaData) => this.resolveRuleChainMetadata(savedRuleChainMetaData)) - ); - } - - public resolveRuleChainMetadata(ruleChainMetaData: RuleChainMetaData): Observable { - return this.resolveTargetRuleChains(ruleChainMetaData.ruleChainConnections).pipe( - map((targetRuleChainsMap) => { - const resolvedRuleChainMetadata: ResolvedRuleChainMetaData = {...ruleChainMetaData, targetRuleChainsMap}; - return resolvedRuleChainMetadata; - }) - ); - } - public getRuleNodeComponents(modulesMap: IModulesMap, ruleChainType: RuleChainType, config?: RequestConfig): Observable> { if (this.ruleNodeComponentsMap.get(ruleChainType)) { @@ -130,7 +109,6 @@ export class RuleChainService { return this.resolveRuleNodeComponentsUiResources(components, modulesMap).pipe( map((ruleNodeComponents) => { this.ruleNodeComponentsMap.set(ruleChainType, ruleNodeComponents); - this.ruleNodeComponentsMap.get(ruleChainType).push(ruleChainNodeComponent); this.ruleNodeComponentsMap.get(ruleChainType).sort( (comp1, comp2) => { let result = comp1.type.toString().localeCompare(comp2.type.toString()); @@ -180,6 +158,14 @@ export class RuleChainService { return component.configurationDescriptor.nodeDefinition.customRelations; } + public ruleNodeSourceRuleChainId(component: RuleNodeComponentDescriptor, config: RuleNodeConfiguration): string { + if (component.configurationDescriptor.nodeDefinition.ruleChainNode) { + return config?.ruleChainId; + } else { + return null; + } + } + public getLatestRuleNodeDebugInput(ruleNodeId: string, config?: RequestConfig): Observable { return this.http.get(`/api/ruleNode/${ruleNodeId}/debugIn`, defaultHttpOptionsFromConfig(config)); } @@ -188,26 +174,6 @@ export class RuleChainService { return this.http.post('/api/ruleChain/testScript', inputParams, defaultHttpOptionsFromConfig(config)); } - private resolveTargetRuleChains(ruleChainConnections: Array): Observable<{[ruleChainId: string]: RuleChain}> { - if (ruleChainConnections && ruleChainConnections.length) { - const tasks: Observable[] = []; - ruleChainConnections.forEach((connection) => { - tasks.push(this.resolveRuleChain(connection.targetRuleChainId.id)); - }); - return forkJoin(tasks).pipe( - map((ruleChains) => { - const ruleChainsMap: {[ruleChainId: string]: RuleChain} = {}; - ruleChains.forEach((ruleChain) => { - ruleChainsMap[ruleChain.id.id] = ruleChain; - }); - return ruleChainsMap; - }) - ); - } else { - return of({} as {[ruleChainId: string]: RuleChain}); - } - } - private loadRuleNodeComponents(ruleChainType: RuleChainType, config?: RequestConfig): Observable> { return this.componentDescriptorService.getComponentDescriptorsByTypes(ruleNodeTypeComponentTypes, ruleChainType, config).pipe( map((components) => { @@ -228,7 +194,7 @@ export class RuleChainService { tasks.push(this.resolveRuleNodeComponentUiResources(component, modulesMap)); }); return forkJoin(tasks).pipe( - catchError((err) => { + catchError(() => { return of(components); }) ); @@ -268,7 +234,7 @@ export class RuleChainService { )); } return forkJoin(tasks).pipe( - map((res) => { + map(() => { return component; }), catchError(() => { @@ -281,21 +247,6 @@ export class RuleChainService { } } - private resolveRuleChain(ruleChainId: string): Observable { - return this.getRuleChain(ruleChainId, {ignoreErrors: true}).pipe( - map(ruleChain => ruleChain), - catchError((err) => { - const ruleChain = { - id: { - entityType: EntityType.RULE_CHAIN, - id: ruleChainId - } - } as RuleChain; - return of(ruleChain); - }) - ); - } - public getEdgeRuleChains(edgeId: string, pageLink: PageLink, config?: RequestConfig): Observable> { return this.http.get>(`/api/edge/${edgeId}/ruleChains${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); diff --git a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts index 61cc7ae478..20e21f0aad 100644 --- a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts +++ b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts @@ -423,7 +423,7 @@ export class ImportExportService { public importRuleChain(expectedRuleChainType: RuleChainType): Observable { return this.openImportDialog('rulechain.import', 'rulechain.rulechain-file').pipe( - mergeMap((ruleChainImport: RuleChainImport) => { + map((ruleChainImport: RuleChainImport) => { if (!this.validateImportedRuleChain(ruleChainImport)) { this.store.dispatch(new ActionNotificationShow( {message: this.translate.instant('rulechain.invalid-rulechain-file-error'), @@ -435,12 +435,7 @@ export class ImportExportService { type: 'error'})); throw new Error('Invalid rule chain type'); } else { - return this.ruleChainService.resolveRuleChainMetadata(ruleChainImport.metadata).pipe( - map((resolvedMetadata) => { - ruleChainImport.resolvedMetadata = resolvedMetadata; - return ruleChainImport; - }) - ); + return ruleChainImport; } }), catchError((err) => { diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts b/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts index 4ffa51a6bd..32147ff475 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts @@ -18,7 +18,7 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { EntitiesTableComponent } from '@home/components/entity/entities-table.component'; import { Authority } from '@shared/models/authority.enum'; -import { EdgesTableConfigResolver } from '@home/pages/edge/edges-table-config.resolver' +import { EdgesTableConfigResolver } from '@home/pages/edge/edges-table-config.resolver'; import { AssetsTableConfigResolver } from '@home/pages/asset/assets-table-config.resolver'; import { DevicesTableConfigResolver } from '@home/pages/device/devices-table-config.resolver'; import { EntityViewsTableConfigResolver } from '@home/pages/entity-view/entity-views-table-config.resolver'; @@ -32,7 +32,7 @@ import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { RuleChainType } from '@shared/models/rule-chain.models'; import { importRuleChainBreadcumbLabelFunction, - ResolvedRuleChainMetaDataResolver, + RuleChainMetaDataResolver, ruleChainBreadcumbLabelFunction, RuleChainImportGuard, RuleChainResolver, @@ -181,7 +181,7 @@ const routes: Routes = [ }, resolve: { ruleChain: RuleChainResolver, - ruleChainMetaData: ResolvedRuleChainMetaDataResolver, + ruleChainMetaData: RuleChainMetaDataResolver, ruleNodeComponents: RuleNodeComponentsResolver, tooltipster: TooltipsterResolver } @@ -243,7 +243,7 @@ const routes: Routes = [ }, resolve: { ruleChain: RuleChainResolver, - ruleChainMetaData: ResolvedRuleChainMetaDataResolver, + ruleChainMetaData: RuleChainMetaDataResolver, ruleNodeComponents: RuleNodeComponentsResolver, tooltipster: TooltipsterResolver } diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-link-dialog.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-link-dialog.component.html index 3ae5bfeb1c..05aafce2c5 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-link-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-link-dialog.component.html @@ -34,7 +34,8 @@ required formControlName="link" [allowedLabels]="labels" - [allowCustom]="allowCustomLabels"> + [allowCustom]="allowCustomLabels" + [sourceRuleChainId]="sourceRuleChainId"> diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.ts index acfca56c16..66be6c0f51 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.ts @@ -25,7 +25,8 @@ import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material import { MatChipInputEvent, MatChipList } from '@angular/material/chips'; import { TranslateService } from '@ngx-translate/core'; import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; -import { map, mergeMap, share, startWith } from 'rxjs/operators'; +import { catchError, map, mergeMap, share, startWith } from 'rxjs/operators'; +import { RuleChainService } from '@core/http/rule-chain.service'; @Component({ selector: 'tb-link-labels', @@ -68,6 +69,9 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan @Input() allowedLabels: {[label: string]: LinkLabel}; + @Input() + sourceRuleChainId: string; + linksFormGroup: FormGroup; modelValue: Array; @@ -86,7 +90,8 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan constructor(private fb: FormBuilder, public truncate: TruncatePipe, - public translate: TranslateService) { + public translate: TranslateService, + private ruleChainService: RuleChainService) { this.linksFormGroup = this.fb.group({ label: [null] }); @@ -115,7 +120,7 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan for (const propName of Object.keys(changes)) { const change = changes[propName]; if (change.currentValue !== change.previousValue) { - if (['allowCustom', 'allowedLabels'].includes(propName)) { + if (['allowCustom', 'allowedLabels', 'sourceRuleChainId'].includes(propName)) { reloadLabels = true; } } @@ -139,25 +144,50 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan this.labelsList.length = 0; this.labels.length = 0; this.modelValue = value; - for (const label of Object.keys(this.allowedLabels)) { - this.labelsList.push({name: this.allowedLabels[label].name, value: this.allowedLabels[label].value}); - } - if (value) { - value.forEach((label) => { - if (this.allowedLabels[label]) { - this.labels.push(deepClone(this.allowedLabels[label])); - } else { - this.labels.push({ - name: label, - value: label - }); - } - }); - } - if (this.chipList && this.required) { - this.chipList.errorState = this.labels.length ? false : true; + this.prepareLabelsList().subscribe((labelsList) => { + this.labelsList = labelsList; + if (value) { + value.forEach((label) => { + if (this.allowedLabels[label]) { + this.labels.push(deepClone(this.allowedLabels[label])); + } else { + this.labels.push({ + name: label, + value: label + }); + } + }); + } + if (this.chipList && this.required) { + this.chipList.errorState = !this.labels.length; + } + this.linksFormGroup.get('label').patchValue('', {emitEvent: true}); + }); + } + + prepareLabelsList(): Observable> { + const labelsList: Array = []; + if (this.sourceRuleChainId) { + return this.ruleChainService.getRuleChainOutputLabels(this.sourceRuleChainId, {ignoreErrors: true}).pipe( + map((labels) => { + for (const label of labels) { + labelsList.push({ + name: label, + value: label + }); + } + return labelsList; + }), + catchError(() => { + return of(labelsList); + }) + ); + } else { + for (const label of Object.keys(this.allowedLabels)) { + labelsList.push({name: this.allowedLabels[label].name, value: this.allowedLabels[label].value}); + } + return of(labelsList); } - this.linksFormGroup.get('label').patchValue('', {emitEvent: true}); } displayLabelFn(label?: LinkLabel): string | undefined { @@ -165,7 +195,7 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan } textIsNotEmpty(text: string): boolean { - return (text && text != null && text.length > 0) ? true : false; + return (text && text.length > 0); } createLinkLabel($event: Event, value: string) { diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-colors.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-colors.scss index a0896dbacd..07f2b66d50 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-colors.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-colors.scss @@ -34,7 +34,7 @@ background-color: #fbc766; } - &.tb-rule-chain-type { + &.tb-flow-type { background-color: #d6c4f1; } diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts index f709da687f..8fd4778abe 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts @@ -37,6 +37,7 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { TranslateService } from '@ngx-translate/core'; import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component'; import { deepClone } from '@core/utils'; +import { RuleChainType } from '@shared/models/rule-chain.models'; @Component({ selector: 'tb-rule-node-config', @@ -69,6 +70,12 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On @Input() ruleNodeId: string; + @Input() + ruleChainId: string; + + @Input() + ruleChainType: RuleChainType; + nodeDefinitionValue: RuleNodeDefinition; @Input() @@ -186,6 +193,8 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On this.definedConfigComponentRef = this.definedConfigContainer.createComponent(factory); this.definedConfigComponent = this.definedConfigComponentRef.instance; this.definedConfigComponent.ruleNodeId = this.ruleNodeId; + this.definedConfigComponent.ruleChainId = this.ruleChainId; + this.definedConfigComponent.ruleChainType = this.ruleChainType; this.definedConfigComponent.configuration = this.configuration; this.changeSubscription = this.definedConfigComponent.configurationChanged.subscribe((configuration) => { this.updateModel(configuration); diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html index 451b8ad8ee..e390175682 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
        +
        -
        +
        rulenode.name @@ -43,6 +43,8 @@
        @@ -52,19 +54,5 @@
        -
        - - -
        - - rulenode.description - - -
        -
        diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts index 4627b2a06b..861f6123e1 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts @@ -75,28 +75,16 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O this.ruleNodeFormSubscription = null; } if (this.ruleNode) { - if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) { - - this.ruleNodeFormGroup = this.fb.group({ - name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*'), Validators.maxLength(255)]], - debugMode: [this.ruleNode.debugMode, []], - configuration: [this.ruleNode.configuration, [Validators.required]], - additionalInfo: this.fb.group( - { - description: [this.ruleNode.additionalInfo ? this.ruleNode.additionalInfo.description : ''], - } - ) - }); - } else { - this.ruleNodeFormGroup = this.fb.group({ - targetRuleChainId: [this.ruleNode.targetRuleChainId, [Validators.required]], - additionalInfo: this.fb.group( - { - description: [this.ruleNode.additionalInfo ? this.ruleNode.additionalInfo.description : ''], - } - ) - }); - } + this.ruleNodeFormGroup = this.fb.group({ + name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*'), Validators.maxLength(255)]], + debugMode: [this.ruleNode.debugMode, []], + configuration: [this.ruleNode.configuration, [Validators.required]], + additionalInfo: this.fb.group( + { + description: [this.ruleNode.additionalInfo ? this.ruleNode.additionalInfo.description : ''], + } + ) + }); this.ruleNodeFormSubscription = this.ruleNodeFormGroup.valueChanges.subscribe(() => { this.updateRuleNode(); }); @@ -107,23 +95,8 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O private updateRuleNode() { const formValue = this.ruleNodeFormGroup.value || {}; - - if (this.ruleNode.component.type === RuleNodeType.RULE_CHAIN) { - const targetRuleChainId: string = formValue.targetRuleChainId; - if (this.ruleNode.targetRuleChainId !== targetRuleChainId && targetRuleChainId) { - this.ruleChainService.getRuleChain(targetRuleChainId).subscribe( - (ruleChain) => { - this.ruleNode.name = ruleChain.name; - Object.assign(this.ruleNode, formValue); - } - ); - } else { - Object.assign(this.ruleNode, formValue); - } - } else { - formValue.name = formValue.name.trim(); - Object.assign(this.ruleNode, formValue); - } + formValue.name = formValue.name.trim(); + Object.assign(this.ruleNode, formValue); } ngOnInit(): void { @@ -141,20 +114,19 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O } validate() { - if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) { - this.ruleNodeConfigComponent.validate(); - } + this.ruleNodeConfigComponent.validate(); } openRuleChain($event: Event) { if ($event) { $event.stopPropagation(); } - if (this.ruleNode.targetRuleChainId) { + const ruleChainId = this.ruleNodeFormGroup.get('configuration')?.value?.ruleChainId; + if (ruleChainId) { if (this.ruleChainType === RuleChainType.EDGE) { - this.router.navigateByUrl(`/edgeManagement/ruleChains/${this.ruleNode.targetRuleChainId}`); + this.router.navigateByUrl(`/edgeManagement/ruleChains/${ruleChainId}`); } else { - this.router.navigateByUrl(`/ruleChains/${this.ruleNode.targetRuleChainId}`); + this.router.navigateByUrl(`/ruleChains/${ruleChainId}`); } } } diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.html index 564017b7c9..7a62dd7105 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.html @@ -22,6 +22,7 @@ formControlName="labels" [allowedLabels]="allowedLabels" [allowCustom]="allowCustom" + [sourceRuleChainId]="sourceRuleChainId" >
        diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts index 8ca7cf190b..7c14097979 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts @@ -57,6 +57,9 @@ export class RuleNodeLinkComponent implements ControlValueAccessor, OnInit { @Input() allowedLabels: {[label: string]: LinkLabel}; + @Input() + sourceRuleChainId: string; + ruleNodeLinkFormGroup: FormGroup; modelValue: FcRuleEdge; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html index 997cfb3cd5..1daaab95da 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html @@ -158,7 +158,8 @@ #tbRuleNodeLink [(ngModel)]="editingRuleNodeLink" [allowedLabels]="editingRuleNodeLinkLabels" - [allowCustom]="editingRuleNodeAllowCustomLabels"> + [allowCustom]="editingRuleNodeAllowCustomLabels" + [sourceRuleChainId]="editingRuleNodeSourceRuleChainId"> diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss index aab0c4d127..24b1ecc9b0 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss @@ -184,7 +184,7 @@ display: block; position: absolute; top: 11px; - right: -12px; + right: 10px; border: 1px solid #FFFFFF; border-radius: 4px; line-height: 18px; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index cc2c6c903d..8784716861 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -43,12 +43,10 @@ import { ActivatedRoute, Router } from '@angular/router'; import { inputNodeComponent, NodeConnectionInfo, - ResolvedRuleChainMetaData, RuleChain, - RuleChainConnectionInfo, RuleChainImport, RuleChainMetaData, - ruleChainNodeComponent, RuleChainType + RuleChainType } from '@shared/models/rule-chain.models'; import { FcItemInfo, FlowchartConstants, NgxFlowchartComponent, UserCallbacks } from 'ngx-flowchart'; import { @@ -75,7 +73,6 @@ import { DialogComponent } from '@shared/components/dialog.component'; import { MatMenuTrigger } from '@angular/material/menu'; import { ItemBufferService, RuleNodeConnection } from '@core/services/item-buffer.service'; import { Hotkey } from 'angular2-hotkeys'; -import { EntityType } from '@shared/models/entity-type.models'; import { DebugEventType, EventType } from '@shared/models/event.models'; import Timeout = NodeJS.Timeout; @@ -130,6 +127,7 @@ export class RuleChainPageComponent extends PageComponent editingRuleNodeIndex = -1; editingRuleNodeAllowCustomLabels = false; editingRuleNodeLinkLabels: {[label: string]: LinkLabel}; + editingRuleNodeSourceRuleChainId: string; @ViewChild('tbRuleNode') ruleNodeComponent: RuleNodeDetailsComponent; @ViewChild('tbRuleNodeLink') ruleNodeLinkComponent: RuleNodeLinkComponent; @@ -147,7 +145,7 @@ export class RuleChainPageComponent extends PageComponent ruleNodeTypeSearch = ''; ruleChain: RuleChain; - ruleChainMetaData: ResolvedRuleChainMetaData; + ruleChainMetaData: RuleChainMetaData; ruleChainModel: FcRuleNodeModel = { nodes: [], @@ -179,16 +177,11 @@ export class RuleChainPageComponent extends PageComponent createEdge: (event, edge: FcRuleEdge) => { const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.source) as FcRuleNode; if (sourceNode.component.type === RuleNodeType.INPUT) { - const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination) as FcRuleNode; - if (destNode.component.type === RuleNodeType.RULE_CHAIN) { - return NEVER; - } else { - const found = this.ruleChainModel.edges.find(theEdge => theEdge.source === (this.inputConnectorId + '')); - if (found) { - this.ruleChainCanvas.modelService.edges.delete(found); - } - return of(edge); + const found = this.ruleChainModel.edges.find(theEdge => theEdge.source === (this.inputConnectorId + '')); + if (found) { + this.ruleChainCanvas.modelService.edges.delete(found); } + return of(edge); } else { if (edge.label) { if (!edge.labels) { @@ -198,8 +191,9 @@ export class RuleChainPageComponent extends PageComponent } else { const labels = this.ruleChainService.getRuleNodeSupportedLinks(sourceNode.component); const allowCustomLabels = this.ruleChainService.ruleNodeAllowCustomLinks(sourceNode.component); + const sourceRuleChainId = this.ruleChainService.ruleNodeSourceRuleChainId(sourceNode.component, sourceNode.configuration); this.enableHotKeys = false; - return this.addRuleNodeLink(edge, labels, allowCustomLabels).pipe( + return this.addRuleNodeLink(edge, labels, allowCustomLabels, sourceRuleChainId).pipe( tap(() => { this.enableHotKeys = true; }), @@ -294,7 +288,7 @@ export class RuleChainPageComponent extends PageComponent if (this.isImport) { const ruleChainImport: RuleChainImport = this.itembuffer.getRuleChainImport(); this.ruleChain = ruleChainImport.ruleChain; - this.ruleChainMetaData = ruleChainImport.resolvedMetadata; + this.ruleChainMetaData = ruleChainImport.metadata; } else { this.ruleChain = this.route.snapshot.data.ruleChain; this.ruleChainMetaData = this.route.snapshot.data.ruleChainMetaData; @@ -601,63 +595,6 @@ export class RuleChainPageComponent extends PageComponent } }); } - if (this.ruleChainMetaData.ruleChainConnections) { - const ruleChainsMap = this.ruleChainMetaData.targetRuleChainsMap; - const ruleChainNodesMap: {[ruleChainNodeId: string]: FcRuleNode} = {}; - const ruleChainEdgeMap: {[edgeKey: string]: FcRuleEdge} = {}; - this.ruleChainMetaData.ruleChainConnections.forEach((ruleChainConnection) => { - const ruleChain = ruleChainsMap[ruleChainConnection.targetRuleChainId.id]; - if (ruleChainConnection.additionalInfo && ruleChainConnection.additionalInfo.ruleChainNodeId) { - let ruleChainNode = ruleChainNodesMap[ruleChainConnection.additionalInfo.ruleChainNodeId]; - if (!ruleChainNode) { - ruleChainNode = { - id: 'rule-chain-node-' + this.nextNodeID++, - name: ruleChain.name ? ruleChain.name : 'Unresolved', - targetRuleChainId: ruleChain.name ? ruleChainConnection.targetRuleChainId.id : null, - error: ruleChain.name ? undefined : this.translate.instant('rulenode.invalid-target-rulechain'), - additionalInfo: ruleChainConnection.additionalInfo, - x: Math.round(ruleChainConnection.additionalInfo.layoutX), - y: Math.round(ruleChainConnection.additionalInfo.layoutY), - component: ruleChainNodeComponent, - nodeClass: ruleNodeTypeDescriptors.get(RuleNodeType.RULE_CHAIN).nodeClass, - icon: ruleNodeTypeDescriptors.get(RuleNodeType.RULE_CHAIN).icon, - connectors: [ - { - type: FlowchartConstants.leftConnectorType, - id: (this.nextConnectorID++) + '' - } - ], - ruleChainType: this.ruleChainType - }; - ruleChainNodesMap[ruleChainConnection.additionalInfo.ruleChainNodeId] = ruleChainNode; - this.ruleChainModel.nodes.push(ruleChainNode); - } - const sourceNode = nodes[ruleChainConnection.fromIndex]; - if (sourceNode) { - const connectors = sourceNode.connectors.filter(connector => connector.type === FlowchartConstants.rightConnectorType); - if (connectors && connectors.length) { - const sourceId = connectors[0].id; - const destId = ruleChainNode.connectors[0].id; - const edgeKey = sourceId + '_' + destId; - let ruleChainEdge = ruleChainEdgeMap[edgeKey]; - if (!ruleChainEdge) { - ruleChainEdge = { - source: sourceId, - destination: destId, - label: ruleChainConnection.type, - labels: [ruleChainConnection.type] - }; - ruleChainEdgeMap[edgeKey] = ruleChainEdge; - this.ruleChainModel.edges.push(ruleChainEdge); - } else { - ruleChainEdge.label += ' / ' + ruleChainConnection.type; - ruleChainEdge.labels.push(ruleChainConnection.type); - } - } - } - } - }); - } if (this.ruleChainCanvas) { this.ruleChainCanvas.adjustCanvasSize(true); } @@ -918,6 +855,8 @@ export class RuleChainPageComponent extends PageComponent this.editingRuleNode = null; this.editingRuleNodeLinkLabels = this.ruleChainService.getRuleNodeSupportedLinks(sourceNode.component); this.editingRuleNodeAllowCustomLabels = this.ruleChainService.ruleNodeAllowCustomLinks(sourceNode.component); + this.editingRuleNodeSourceRuleChainId = + this.ruleChainService.ruleNodeSourceRuleChainId(sourceNode.component, sourceNode.configuration); this.isEditingRuleNodeLink = true; this.editingRuleNodeLinkIndex = this.ruleChainModel.edges.indexOf(edge); this.editingRuleNodeLink = deepClone(edge); @@ -1093,7 +1032,7 @@ export class RuleChainPageComponent extends PageComponent const type = ruleNodeTypeDescriptors.get(ruleNodeType); this.displayTooltip(event, '
        ' + - '
        ' + + '
        ' + '
        ' + this.translate.instant(type.name) + '
        ' + '
        ' + this.translate.instant(type.details) + '
        ' + '
        ' + @@ -1104,7 +1043,7 @@ export class RuleChainPageComponent extends PageComponent displayLibNodeDescriptionTooltip(event: MouseEvent, node: FcRuleNodeType) { this.displayTooltip(event, '
        ' + - '
        ' + + '
        ' + '
        ' + node.component.name + '
        ' + '
        ' + node.component.configurationDescriptor.nodeDefinition.description + '
        ' + '
        ' + node.component.configurationDescriptor.nodeDefinition.details + '
        ' + @@ -1129,7 +1068,7 @@ export class RuleChainPageComponent extends PageComponent } } let tooltipContent = '
        ' + - '
        ' + + '
        ' + '
        ' + name + '
        ' + '
        ' + desc + '
        '; if (details) { @@ -1189,7 +1128,7 @@ export class RuleChainPageComponent extends PageComponent resetDebugModeInAllNodes() { let changed = false; this.ruleChainModel.nodes.forEach((node) => { - if (node.component.type !== RuleNodeType.INPUT && node.component.type !== RuleNodeType.RULE_CHAIN) { + if (node.component.type !== RuleNodeType.INPUT) { changed = changed || node.debugMode; node.debugMode = false; } @@ -1223,12 +1162,11 @@ export class RuleChainPageComponent extends PageComponent const ruleChainMetaData: RuleChainMetaData = { ruleChainId: this.ruleChain.id, nodes: [], - connections: [], - ruleChainConnections: [] + connections: [] }; const nodes: FcRuleNode[] = []; this.ruleChainModel.nodes.forEach((node) => { - if (node.component.type !== RuleNodeType.INPUT && node.component.type !== RuleNodeType.RULE_CHAIN) { + if (node.component.type !== RuleNodeType.INPUT) { const ruleNode: RuleNode = { id: node.ruleNodeId, type: node.component.clazz, @@ -1253,35 +1191,19 @@ export class RuleChainPageComponent extends PageComponent const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination); if (sourceNode.component.type !== RuleNodeType.INPUT) { const fromIndex = nodes.indexOf(sourceNode); - if (destNode.component.type === RuleNodeType.RULE_CHAIN) { - const ruleChainConnection = { - fromIndex, - targetRuleChainId: {entityType: EntityType.RULE_CHAIN, id: destNode.targetRuleChainId}, - additionalInfo: destNode.additionalInfo ? destNode.additionalInfo : {} - } as RuleChainConnectionInfo; - ruleChainConnection.additionalInfo.layoutX = Math.round(destNode.x); - ruleChainConnection.additionalInfo.layoutY = Math.round(destNode.y); - ruleChainConnection.additionalInfo.ruleChainNodeId = destNode.id; - edge.labels.forEach((label) => { - const newRuleChainConnection = deepClone(ruleChainConnection); - newRuleChainConnection.type = label; - ruleChainMetaData.ruleChainConnections.push(newRuleChainConnection); - }); - } else { - const toIndex = nodes.indexOf(destNode); - const nodeConnection = { - fromIndex, - toIndex - } as NodeConnectionInfo; - edge.labels.forEach((label) => { - const newNodeConnection = deepClone(nodeConnection); - newNodeConnection.type = label; - ruleChainMetaData.connections.push(newNodeConnection); - }); - } + const toIndex = nodes.indexOf(destNode); + const nodeConnection = { + fromIndex, + toIndex + } as NodeConnectionInfo; + edge.labels.forEach((label) => { + const newNodeConnection = deepClone(nodeConnection); + newNodeConnection.type = label; + ruleChainMetaData.connections.push(newNodeConnection); + }); } }); - this.ruleChainService.saveAndGetResolvedRuleChainMetadata(ruleChainMetaData).subscribe((savedRuleChainMetaData) => { + this.ruleChainService.saveRuleChainMetadata(ruleChainMetaData).subscribe((savedRuleChainMetaData) => { this.ruleChainMetaData = savedRuleChainMetaData; if (this.isImport) { this.isDirtyValue = false; @@ -1346,7 +1268,8 @@ export class RuleChainPageComponent extends PageComponent ); } - addRuleNodeLink(link: FcRuleEdge, labels: {[label: string]: LinkLabel}, allowCustomLabels: boolean): Observable { + addRuleNodeLink(link: FcRuleEdge, labels: {[label: string]: LinkLabel}, + allowCustomLabels: boolean, sourceRuleChainId: string): Observable { return this.dialog.open(AddRuleNodeLinkDialogComponent, { disableClose: true, @@ -1354,7 +1277,8 @@ export class RuleChainPageComponent extends PageComponent data: { link, labels, - allowCustomLabels + allowCustomLabels, + sourceRuleChainId } }).afterClosed(); } @@ -1384,7 +1308,7 @@ export class RuleChainPageComponent extends PageComponent } ); const content = '
        ' + - '
        ' + + '
        ' + '
        ' + node.error + '
        ' + '
        ' + '
        '; @@ -1452,6 +1376,7 @@ export interface AddRuleNodeLinkDialogData { link: FcRuleEdge; labels: {[label: string]: LinkLabel}; allowCustomLabels: boolean; + sourceRuleChainId: string; } @Component({ @@ -1468,6 +1393,7 @@ export class AddRuleNodeLinkDialogComponent extends DialogComponent { } @Injectable() -export class ResolvedRuleChainMetaDataResolver implements Resolve { +export class RuleChainMetaDataResolver implements Resolve { constructor(private ruleChainService: RuleChainService) { } - resolve(route: ActivatedRouteSnapshot): Observable { + resolve(route: ActivatedRouteSnapshot): Observable { const ruleChainId = route.params.ruleChainId; - return this.ruleChainService.getResolvedRuleChainMetadata(ruleChainId); + return this.ruleChainService.getRuleChainMetadata(ruleChainId); } } @@ -160,7 +160,7 @@ const routes: Routes = [ }, resolve: { ruleChain: RuleChainResolver, - ruleChainMetaData: ResolvedRuleChainMetaDataResolver, + ruleChainMetaData: RuleChainMetaDataResolver, ruleNodeComponents: RuleNodeComponentsResolver, tooltipster: TooltipsterResolver } @@ -196,7 +196,7 @@ const routes: Routes = [ providers: [ RuleChainsTableConfigResolver, RuleChainResolver, - ResolvedRuleChainMetaDataResolver, + RuleChainMetaDataResolver, RuleNodeComponentsResolver, TooltipsterResolver, RuleChainImportGuard diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.html index da53c21a08..3de5679cc5 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.html @@ -59,8 +59,8 @@ ×
        -
        -
        +
        +
        diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts index ce7ff340d5..6825f7b5ff 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts @@ -20,6 +20,7 @@ import { FcNodeComponent } from 'ngx-flowchart'; import { FcRuleNode, RuleNodeType } from '@shared/models/rule-node.models'; import { Router } from '@angular/router'; import { RuleChainType } from '@app/shared/models/rule-chain.models'; +import { TranslateService } from '@ngx-translate/core'; @Component({ // tslint:disable-next-line:component-selector @@ -33,6 +34,7 @@ export class RuleNodeComponent extends FcNodeComponent implements OnInit { RuleNodeType = RuleNodeType; constructor(private sanitizer: DomSanitizer, + private translate: TranslateService, private router: Router) { super(); } @@ -48,13 +50,48 @@ export class RuleNodeComponent extends FcNodeComponent implements OnInit { if ($event) { $event.stopPropagation(); } - if (node.targetRuleChainId) { + if (node.configuration?.ruleChainId) { if (node.ruleChainType === RuleChainType.EDGE) { - this.router.navigateByUrl(`/edgeManagement/ruleChains/${node.targetRuleChainId}`); + this.router.navigateByUrl(`/edgeManagement/ruleChains/${node.configuration?.ruleChainId}`); } else { - this.router.navigateByUrl(`/ruleChains/${node.targetRuleChainId}`); + this.router.navigateByUrl(`/ruleChains/${node.configuration?.ruleChainId}`); } } } + + displayOpenRuleChainTooltip($event: MouseEvent, node: FcRuleNode) { + if ($event) { + $event.stopPropagation(); + } + this.userNodeCallbacks.mouseLeave($event, node); + const tooltipContent = '
        ' + + '
        ' + + '
        ' + this.translate.instant('rulechain.open-rulechain') + '
        '; + const element = $($event.target); + element.tooltipster( + { + theme: 'tooltipster-shadow', + delay: 100, + trigger: 'custom', + triggerOpen: { + click: false, + tap: false + }, + triggerClose: { + click: true, + tap: true, + scroll: true, + mouseleave: true + }, + side: 'top', + distance: 12, + trackOrigin: true + } + ); + const tooltip = element.tooltipster('instance'); + const contentElement = $(tooltipContent); + tooltip.content(contentElement); + tooltip.open(); + } } diff --git a/ui-ngx/src/app/shared/models/component-descriptor.models.ts b/ui-ngx/src/app/shared/models/component-descriptor.models.ts index e266113848..068a902b18 100644 --- a/ui-ngx/src/app/shared/models/component-descriptor.models.ts +++ b/ui-ngx/src/app/shared/models/component-descriptor.models.ts @@ -21,7 +21,8 @@ export enum ComponentType { FILTER = 'FILTER', TRANSFORMATION = 'TRANSFORMATION', ACTION = 'ACTION', - EXTERNAL = 'EXTERNAL' + EXTERNAL = 'EXTERNAL', + FLOW = 'FLOW' } export enum ComponentScope { diff --git a/ui-ngx/src/app/shared/models/rule-chain.models.ts b/ui-ngx/src/app/shared/models/rule-chain.models.ts index 925ad0b432..61f70bfcb6 100644 --- a/ui-ngx/src/app/shared/models/rule-chain.models.ts +++ b/ui-ngx/src/app/shared/models/rule-chain.models.ts @@ -38,17 +38,11 @@ export interface RuleChainMetaData { firstNodeIndex?: number; nodes: Array; connections: Array; - ruleChainConnections: Array; -} - -export interface ResolvedRuleChainMetaData extends RuleChainMetaData { - targetRuleChainsMap: {[ruleChainId: string]: RuleChain}; } export interface RuleChainImport { ruleChain: RuleChain; metadata: RuleChainMetaData; - resolvedMetadata?: ResolvedRuleChainMetaData; } export interface NodeConnectionInfo { @@ -57,39 +51,16 @@ export interface NodeConnectionInfo { type: string; } -export interface RuleChainConnectionInfo { - fromIndex: number; - targetRuleChainId: RuleChainId; - additionalInfo: any; - type: string; -} - export const ruleNodeTypeComponentTypes: ComponentType[] = [ ComponentType.FILTER, ComponentType.ENRICHMENT, ComponentType.TRANSFORMATION, ComponentType.ACTION, - ComponentType.EXTERNAL + ComponentType.EXTERNAL, + ComponentType.FLOW ]; -export const ruleChainNodeComponent: RuleNodeComponentDescriptor = { - type: RuleNodeType.RULE_CHAIN, - name: 'rule chain', - clazz: 'tb.internal.RuleChain', - configurationDescriptor: { - nodeDefinition: { - description: '', - details: 'Forwards incoming messages to specified Rule Chain', - inEnabled: true, - outEnabled: false, - relationTypes: [], - customRelations: false, - defaultConfiguration: {} - } - } -}; - export const unknownNodeComponent: RuleNodeComponentDescriptor = { type: RuleNodeType.UNKNOWN, name: 'unknown', diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index 097f8b2edc..ce2563826f 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -52,6 +52,7 @@ export interface RuleNodeDefinition { outEnabled: boolean; relationTypes: string[]; customRelations: boolean; + ruleChainNode?: boolean; defaultConfiguration: RuleNodeConfiguration; icon?: string; iconUrl?: string; @@ -67,6 +68,8 @@ export interface RuleNodeConfigurationDescriptor { export interface IRuleNodeConfigurationComponent { ruleNodeId: string; + ruleChainId: string; + ruleChainType: RuleChainType; configuration: RuleNodeConfiguration; configurationChanged: Observable; validate(); @@ -74,11 +77,16 @@ export interface IRuleNodeConfigurationComponent { } @Directive() +// tslint:disable-next-line:directive-class-suffix export abstract class RuleNodeConfigurationComponent extends PageComponent implements IRuleNodeConfigurationComponent, OnInit, AfterViewInit { ruleNodeId: string; + ruleChainId: string; + + ruleChainType: RuleChainType; + configurationValue: RuleNodeConfiguration; private configurationSet = false; @@ -184,7 +192,7 @@ export enum RuleNodeType { TRANSFORMATION = 'TRANSFORMATION', ACTION = 'ACTION', EXTERNAL = 'EXTERNAL', - RULE_CHAIN = 'RULE_CHAIN', + FLOW = 'FLOW', UNKNOWN = 'UNKNOWN', INPUT = 'INPUT' } @@ -195,7 +203,7 @@ export const ruleNodeTypesLibrary = [ RuleNodeType.TRANSFORMATION, RuleNodeType.ACTION, RuleNodeType.EXTERNAL, - RuleNodeType.RULE_CHAIN, + RuleNodeType.FLOW, ]; export interface RuleNodeTypeDescriptor { @@ -260,12 +268,12 @@ export const ruleNodeTypeDescriptors = new Map Date: Wed, 8 Dec 2021 15:57:52 +0200 Subject: [PATCH 295/303] Removed TODO --- .../org/thingsboard/server/controller/RuleChainController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 9122990339..5357daacce 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -361,7 +361,6 @@ public class RuleChainController extends BaseController { @ApiParam(value = "A JSON value representing the rule chain metadata.") @RequestBody RuleChainMetaData ruleChainMetaData, @ApiParam(value = "Update related rule nodes.") - //TODO: change default value to "false" before merge @RequestParam(value = "updateRelated", required = false, defaultValue = "true") boolean updateRelated ) throws ThingsboardException { try { From b5da8752c57b7c716c1d884f44d6c8c9add3097e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 8 Dec 2021 16:23:54 +0200 Subject: [PATCH 296/303] Use output rule node name instead of label --- .../controller/RuleChainController.java | 4 --- .../rule/DefaultTbRuleChainService.java | 29 ++++++--------- .../data/rule/RuleNodeUpdateResult.java | 3 +- .../server/dao/rule/BaseRuleChainService.java | 4 +-- .../engine/flow/TbRuleChainOutputNode.java | 11 +++--- .../TbRuleChainOutputNodeConfiguration.java | 35 ------------------- .../static/rulenode/rulenode-core-config.js | 9 ++--- 7 files changed, 21 insertions(+), 74 deletions(-) delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 5357daacce..85f469a6c9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -36,10 +36,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.ScriptEngine; -import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; -import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.tenant.DebugTbRateLimits; import org.thingsboard.server.common.data.DataConstants; @@ -71,7 +68,6 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.event.EventService; -import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.rule.TbRuleChainService; diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index e6d1ba1d8a..ff2599c0ff 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -23,7 +23,6 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; -import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; @@ -65,14 +64,7 @@ public class DefaultTbRuleChainService implements TbRuleChainService { Set outputLabels = new TreeSet<>(); for (RuleNode ruleNode : metaData.getNodes()) { if (isOutputRuleNode(ruleNode)) { - try { - var configuration = JacksonUtil.treeToValue(ruleNode.getConfiguration(), TbRuleChainOutputNodeConfiguration.class); - if (StringUtils.isNotEmpty(configuration.getLabel())) { - outputLabels.add(configuration.getLabel()); - } - } catch (Exception e) { - log.warn("[{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, e); - } + outputLabels.add(ruleNode.getName()); } } return outputLabels; @@ -130,16 +122,15 @@ public class DefaultTbRuleChainService implements TbRuleChainService { Set confusedLabels = new HashSet<>(); Map updatedLabels = new HashMap<>(); for (RuleNodeUpdateResult update : result.getUpdatedRuleNodes()) { - var node = update.getNewRuleNode(); - if (isOutputRuleNode(node)) { + var oldNode = update.getOldRuleNode(); + var newNode = update.getNewRuleNode(); + if (isOutputRuleNode(newNode)) { try { - TbRuleChainOutputNodeConfiguration oldConf = JacksonUtil.treeToValue(update.getOldConfiguration(), TbRuleChainOutputNodeConfiguration.class); - TbRuleChainOutputNodeConfiguration newConf = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainOutputNodeConfiguration.class); - oldLabels.add(oldConf.getLabel()); - newLabels.add(newConf.getLabel()); - if (!oldConf.getLabel().equals(newConf.getLabel())) { - String oldLabel = oldConf.getLabel(); - String newLabel = newConf.getLabel(); + oldLabels.add(oldNode.getName()); + newLabels.add(newNode.getName()); + if (!oldNode.getName().equals(newNode.getName())) { + String oldLabel = oldNode.getName(); + String newLabel = newNode.getName(); if (updatedLabels.containsKey(oldLabel) && !updatedLabels.get(oldLabel).equals(newLabel)) { confusedLabels.add(oldLabel); log.warn("[{}][{}] Can't automatically rename the label from [{}] to [{}] due to conflict [{}]", tenantId, ruleChainId, oldLabel, newLabel, updatedLabels.get(oldLabel)); @@ -149,7 +140,7 @@ public class DefaultTbRuleChainService implements TbRuleChainService { } } catch (Exception e) { - log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, node.getId(), e); + log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, newNode.getId(), e); } } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java index a279533138..02f68ea5c2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java @@ -27,6 +27,7 @@ import java.util.Map; @Data public class RuleNodeUpdateResult { - private final JsonNode oldConfiguration; + private final RuleNode oldRuleNode; private final RuleNode newRuleNode; + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index e1aaa31d3c..33ef74db65 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -172,10 +172,10 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC newRuleNode = ruleChainMetaData.getNodes().get(index); toAddOrUpdate.add(newRuleNode); } else { - updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), null)); + updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode, null)); toDelete.add(existingNode); } - updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), newRuleNode)); + updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode, newRuleNode)); } if (nodes != null) { for (RuleNode node : toAddOrUpdate) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java index f5f75f1275..59ddc1c096 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.flow; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; @@ -30,28 +31,24 @@ import org.thingsboard.server.common.msg.TbMsg; @RuleNode( type = ComponentType.FLOW, name = "output", - configClazz = TbRuleChainOutputNodeConfiguration.class, + configClazz = EmptyNodeConfiguration.class, nodeDescription = "transfers the message to the caller rule chain", nodeDetails = "Produces output of the rule chain processing. " + "The output is forwarded to the caller rule chain, as an output of the corresponding \"input\" rule node. " + - "The rule node configuration contains the \"label\" parameter. " + - "This parameter corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ", + "The output rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFlowNodeRuleChainOutputConfig", outEnabled = false ) public class TbRuleChainOutputNode implements TbNode { - private TbRuleChainOutputNodeConfiguration config; - @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbRuleChainOutputNodeConfiguration.class); } @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.output(msg, config.getLabel()); + ctx.output(msg, ctx.getSelf().getName()); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java deleted file mode 100644 index 8d220530c3..0000000000 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.rule.engine.flow; - -import lombok.Data; -import org.thingsboard.rule.engine.api.NodeConfiguration; -import org.thingsboard.rule.engine.api.TbRelationTypes; -import org.thingsboard.server.common.data.DataConstants; - -@Data -public class TbRuleChainOutputNodeConfiguration implements NodeConfiguration { - - private String label; - - @Override - public TbRuleChainOutputNodeConfiguration defaultConfiguration() { - var result = new TbRuleChainOutputNodeConfiguration(); - result.setLabel(TbRelationTypes.SUCCESS); - return result; - } - -} 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 702fdabe6f..54fbc87f07 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 @@ -3728,13 +3728,11 @@ class RuleChainOutputComponent extends RuleNodeConfigurationComponent { return this.ruleChainOutputConfigForm; } onConfigurationSet(configuration) { - this.ruleChainOutputConfigForm = this.fb.group({ - label: [configuration ? configuration.label : null, [Validators.required]] - }); + this.ruleChainOutputConfigForm = this.fb.group({}); } } RuleChainOutputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "
        \n \n tb.rulenode.label\n \n \n {{ 'tb.rulenode.label-required' | translate }}\n \n \n
        \n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "
        \n
        \n
        \n", directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], pipes: { "translate": i4.TranslatePipe } }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, decorators: [{ type: Component, args: [{ @@ -4191,8 +4189,7 @@ function addRuleNodeCoreLocaleEnglish(translate) { 'alarm-severity-pattern-hint': 'Hint: use ${metadataKey} ' + 'for value from metadata, $[messageKey] ' + 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)', - label: 'Label', - 'label-required': 'Label is required' + 'output-node-name-hint': 'The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.' }, 'key-val': { key: 'Key', From 54486049f41f1964897cf2d8077e1a5ddcb160fd Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 8 Dec 2021 16:38:07 +0200 Subject: [PATCH 297/303] Notifications on related rule chain upates --- .../controller/RuleChainController.java | 24 ++++++++++++++----- .../rule/DefaultTbRuleChainService.java | 17 ++++++------- .../service/rule/TbRuleChainService.java | 4 ++-- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 85f469a6c9..2f9e325c8f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -77,6 +77,8 @@ import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -373,23 +375,33 @@ public class RuleChainController extends BaseController { RuleChainUpdateResult result = ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData); checkNotNull(result.isSuccess() ? true : null); + List updatedRuleChains; if (updateRelated && result.isSuccess()) { - tbRuleChainService.updateRelatedRuleChains(tenantId, ruleChainMetaData.getRuleChainId(), result); + updatedRuleChains = tbRuleChainService.updateRelatedRuleChains(tenantId, ruleChainMetaData.getRuleChainId(), result); + } else { + updatedRuleChains = Collections.emptyList(); } RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId())); if (RuleChainType.CORE.equals(ruleChain.getType())) { tbClusterService.broadcastEntityStateChangeEvent(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED); + updatedRuleChains.forEach(updatedRuleChain -> { + tbClusterService.broadcastEntityStateChangeEvent(updatedRuleChain.getTenantId(), updatedRuleChain.getId(), ComponentLifecycleEvent.UPDATED); + }); } - logEntityAction(ruleChain.getId(), ruleChain, - null, - ActionType.UPDATED, null, ruleChainMetaData); + logEntityAction(ruleChain.getId(), ruleChain, null, ActionType.UPDATED, null, ruleChainMetaData); + for (RuleChain updatedRuleChain : updatedRuleChains) { + RuleChainMetaData updatedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, updatedRuleChain.getId())); + logEntityAction(updatedRuleChain.getId(), updatedRuleChain, null, ActionType.UPDATED, null, updatedRuleChainMetaData); + } if (RuleChainType.EDGE.equals(ruleChain.getType())) { - sendEntityNotificationMsg(ruleChain.getTenantId(), - ruleChain.getId(), EdgeEventActionType.UPDATED); + sendEntityNotificationMsg(ruleChain.getTenantId(), ruleChain.getId(), EdgeEventActionType.UPDATED); + updatedRuleChains.forEach(updatedRuleChain -> { + sendEntityNotificationMsg(updatedRuleChain.getTenantId(), updatedRuleChain.getId(), EdgeEventActionType.UPDATED); + }); } return savedRuleChainMetaData; diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index ff2599c0ff..14f56d1f6b 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.rule; -import com.fasterxml.jackson.core.JsonProcessingException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -23,7 +22,6 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; @@ -37,9 +35,7 @@ import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.security.permission.Operation; -import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -111,10 +107,11 @@ public class DefaultTbRuleChainService implements TbRuleChainService { } @Override - public void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result) { + public List updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result) { + Set ruleChainIds = new HashSet<>(); log.debug("[{}][{}] Going to update links in related rule chains", tenantId, ruleChainId); if (result.getUpdatedRuleNodes() == null || result.getUpdatedRuleNodes().isEmpty()) { - return; + return null; } Set oldLabels = new HashSet<>(); @@ -149,19 +146,23 @@ public class DefaultTbRuleChainService implements TbRuleChainService { // Remove all output labels that are renamed but still present in the rule chain; newLabels.forEach(updatedLabels::remove); if (!oldLabels.equals(newLabels)) { - updateRelatedRuleChains(tenantId, ruleChainId, updatedLabels); + ruleChainIds.addAll(updateRelatedRuleChains(tenantId, ruleChainId, updatedLabels)); } + return ruleChainIds.stream().map(id -> ruleChainService.findRuleChainById(tenantId, id)).collect(Collectors.toList()); } - public void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, Map labelsMap) { + public Set updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, Map labelsMap) { + Set updatedRuleChains = new HashSet<>(); List usageList = getOutputLabelUsage(tenantId, ruleChainId); for (RuleChainOutputLabelsUsage usage : usageList) { labelsMap.forEach((oldLabel, newLabel) -> { if (usage.getLabels().contains(oldLabel)) { + updatedRuleChains.add(usage.getRuleChainId()); renameOutgoingLinks(tenantId, usage.getRuleNodeId(), oldLabel, newLabel); } }); } + return updatedRuleChains; } private void renameOutgoingLinks(TenantId tenantId, RuleNodeId ruleNodeId, String oldLabel, String newLabel) { diff --git a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java index d08f234d8e..ff2d738f9c 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java @@ -15,9 +15,9 @@ */ package org.thingsboard.server.service.rule; -import com.fasterxml.jackson.core.JsonProcessingException; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; @@ -30,5 +30,5 @@ public interface TbRuleChainService { List getOutputLabelUsage(TenantId tenantId, RuleChainId ruleChainId); - void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result); + List updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result); } From c150352ecd22d3fe8149e8b59330000545a822fe Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 8 Dec 2021 18:38:46 +0200 Subject: [PATCH 298/303] Save RuleChain MetaData method fix --- .../server/service/rule/DefaultTbRuleChainService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index 14f56d1f6b..e9795ce15f 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -36,6 +36,7 @@ import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -111,7 +112,7 @@ public class DefaultTbRuleChainService implements TbRuleChainService { Set ruleChainIds = new HashSet<>(); log.debug("[{}][{}] Going to update links in related rule chains", tenantId, ruleChainId); if (result.getUpdatedRuleNodes() == null || result.getUpdatedRuleNodes().isEmpty()) { - return null; + return Collections.emptyList(); } Set oldLabels = new HashSet<>(); From 1d8256b4194647fa09a0d12c4dfa2993ea086324 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 8 Dec 2021 19:13:51 +0200 Subject: [PATCH 299/303] Fix sql upgrade scripts --- application/src/main/data/upgrade/3.3.2/schema_update.sql | 4 ++-- .../server/service/install/SqlDatabaseUpgradeService.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql index 99d2294129..fff08f734c 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -20,8 +20,8 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( created_time bigint NOT NULL, type varchar(255) NOT NULL, customer_id uuid, - alarm_id uuid - CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + alarm_id uuid, + CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); 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 3f9bec2d07..cf34a31006 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 @@ -475,10 +475,10 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); try { - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" + - " select tenant_id, originator_id, created_time, type, customer_id, id, status, severity from alarm;"); - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" + - " select a.tenant_id, r.from_id, created_time, type, customer_id, id, status, severity" + + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + " select tenant_id, originator_id, created_time, type, customer_id, id from alarm;"); + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + " select a.tenant_id, r.from_id, created_time, type, customer_id, id" + " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); } catch (Exception e) { From 8c7f90b74ceab1281547e20d2cc8f86f13d32a4a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 8 Dec 2021 19:39:36 +0200 Subject: [PATCH 300/303] Fix upgrade --- application/src/main/data/upgrade/3.3.2/schema_update.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql index fff08f734c..73e708bf74 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -16,12 +16,13 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( tenant_id uuid NOT NULL, + entity_type varchar(32), entity_id uuid NOT NULL, created_time bigint NOT NULL, - type varchar(255) NOT NULL, + alarm_type varchar(255) NOT NULL, customer_id uuid, alarm_id uuid, - CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), + CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); From eebce55d5a16221356b71430a66e3655bda2b039 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 9 Dec 2021 15:12:03 +0200 Subject: [PATCH 301/303] Improved upgrade script performance --- .../main/data/upgrade/3.3.2/schema_update.sql | 42 +++++- .../install/SqlDatabaseUpgradeService.java | 28 ++-- .../update/DefaultDataUpdateService.java | 126 +++++++++--------- .../server/dao/alarm/AlarmService.java | 2 + .../server/dao/entity/EntityService.java | 2 - .../server/dao/alarm/AlarmDao.java | 2 + .../server/dao/alarm/BaseAlarmService.java | 6 +- .../dao/entity/AbstractEntityService.java | 8 ++ .../server/dao/entity/BaseEntityService.java | 5 - .../dao/relation/BaseRelationService.java | 5 +- .../server/dao/relation/RelationDao.java | 2 +- .../server/dao/rule/BaseRuleChainService.java | 2 - .../dao/sql/alarm/EntityAlarmRepository.java | 3 + .../server/dao/sql/alarm/JpaAlarmDao.java | 6 + .../dao/sql/relation/JpaRelationDao.java | 4 +- .../dao/sql/relation/RelationRepository.java | 12 +- .../main/resources/sql/schema-entities.sql | 2 +- 17 files changed, 156 insertions(+), 101 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql index 73e708bf74..9a8c30ab63 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -22,9 +22,49 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( alarm_type varchar(255) NOT NULL, customer_id uuid, alarm_id uuid, - CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC); CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); + +INSERT INTO entity_alarm(tenant_id, entity_type, entity_id, created_time, alarm_type, customer_id, alarm_id) +SELECT tenant_id, + CASE + WHEN originator_type = 0 THEN 'TENANT' + WHEN originator_type = 1 THEN 'CUSTOMER' + WHEN originator_type = 2 THEN 'USER' + WHEN originator_type = 3 THEN 'DASHBOARD' + WHEN originator_type = 4 THEN 'ASSET' + WHEN originator_type = 5 THEN 'DEVICE' + WHEN originator_type = 6 THEN 'ALARM' + WHEN originator_type = 7 THEN 'RULE_CHAIN' + WHEN originator_type = 8 THEN 'RULE_NODE' + WHEN originator_type = 9 THEN 'ENTITY_VIEW' + WHEN originator_type = 10 THEN 'WIDGETS_BUNDLE' + WHEN originator_type = 11 THEN 'WIDGET_TYPE' + WHEN originator_type = 12 THEN 'TENANT_PROFILE' + WHEN originator_type = 13 THEN 'DEVICE_PROFILE' + WHEN originator_type = 14 THEN 'API_USAGE_STATE' + WHEN originator_type = 15 THEN 'TB_RESOURCE' + WHEN originator_type = 16 THEN 'OTA_PACKAGE' + WHEN originator_type = 17 THEN 'EDGE' + WHEN originator_type = 18 THEN 'RPC' + else 'UNKNOWN' + END, + originator_id, + created_time, + type, + customer_id, + id +FROM alarm +ON CONFLICT DO NOTHING; + +INSERT INTO entity_alarm(tenant_id, entity_type, entity_id, created_time, alarm_type, customer_id, alarm_id) +SELECT a.tenant_id, r.from_type, r.from_id, created_time, type, customer_id, id +FROM alarm a + INNER JOIN relation r ON r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id +ON CONFLICT DO NOTHING; + +DELETE FROM relation r WHERE r.relation_type_group = 'ALARM'; \ No newline at end of file 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 cf34a31006..27e8375dc8 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 @@ -43,6 +43,7 @@ import java.sql.SQLSyntaxErrorException; import java.sql.SQLWarning; import java.sql.Statement; import java.util.List; +import java.util.concurrent.TimeUnit; import static org.thingsboard.server.service.install.DatabaseHelper.ADDITIONAL_INFO; import static org.thingsboard.server.service.install.DatabaseHelper.ASSIGNED_CUSTOMERS; @@ -474,16 +475,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.info("Updating schema ..."); schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); - try { - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + - " select tenant_id, originator_id, created_time, type, customer_id, id from alarm;"); - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + - " select a.tenant_id, r.from_id, created_time, type, customer_id, id" + - " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); - conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); - } catch (Exception e) { - log.error("Failed to update alarm relations!!!", e); - } log.info("Updating schema settings..."); conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); log.info("Schema updated."); @@ -498,10 +489,25 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService private void loadSql(Path sqlFile, Connection conn) throws Exception { String sql = new String(Files.readAllBytes(sqlFile), Charset.forName("UTF-8")); - conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script + Statement st = conn.createStatement(); + st.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(3)); + st.execute(sql);//NOSONAR, ignoring because method used to execute thingsboard database upgrade script + printWarnings(st); Thread.sleep(5000); } + protected void printWarnings(Statement statement) throws SQLException { + SQLWarning warnings = statement.getWarnings(); + if (warnings != null) { + log.info("{}", warnings.getMessage()); + SQLWarning nextWarning = warnings.getNextWarning(); + while (nextWarning != null) { + log.info("{}", nextWarning.getMessage()); + nextWarning = nextWarning.getNextWarning(); + } + } + } + protected boolean isOldSchema(Connection conn, long fromVersion) { boolean isOldSchema = true; try { diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index e244a0f0b0..de8216a4ab 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -139,7 +139,7 @@ public class DefaultDataUpdateService implements DataUpdateService { break; case "3.3.2": log.info("Updating data from version 3.3.2 to 3.3.3 ..."); - nestedRuleNodeUpdater.updateEntities(null); + updateNestedRuleChains(); break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); @@ -225,73 +225,73 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; - private final PaginatedUpdater nestedRuleNodeUpdater = - new PaginatedUpdater<>() { - - @Override - protected String getName() { - return "Tenants nested rule chain updater"; - } - - @Override - protected boolean forceReportTotal() { - return true; - } - - @Override - protected PageData findEntities(String region, PageLink pageLink) { - return tenantService.findTenants(pageLink); - } - - @Override - protected void updateEntity(Tenant tenant) { + private void updateNestedRuleChains() { + try { + var packSize = 1024; + var updated = 0; + boolean hasNext = true; + while (hasNext) { + List relations = relationService.findRuleNodeToRuleChainRelations(TenantId.SYS_TENANT_ID, RuleChainType.CORE, packSize); + hasNext = relations.size() == packSize; + for (EntityRelation relation : relations) { try { - var tenantId = tenant.getId(); - var packSize = 1024; - boolean hasNext = true; - while (hasNext) { - List relations = relationService.findRuleNodeToRuleChainRelations(tenantId, RuleChainType.CORE, packSize); - hasNext = relations.size() == packSize; - for (EntityRelation relation : relations) { - - RuleNode sourceNode = ruleChainService.findRuleNodeById(tenantId, new RuleNodeId(relation.getFrom().getId())); - RuleChainId sourceRuleChainId = sourceNode.getRuleChainId(); - RuleChain targetRuleChain = ruleChainService.findRuleChainById(tenantId, new RuleChainId(relation.getTo().getId())); - RuleNode targetNode = new RuleNode(); - targetNode.setName(targetRuleChain.getName()); - targetNode.setRuleChainId(sourceRuleChainId); - targetNode.setType(TbRuleChainInputNode.class.getName()); - TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration(); - configuration.setRuleChainId(targetRuleChain.getId().toString()); - targetNode.setConfiguration(JacksonUtil.valueToTree(configuration)); - targetNode.setAdditionalInfo(relation.getAdditionalInfo()); - targetNode.setDebugMode(false); - targetNode = ruleChainService.saveRuleNode(tenantId, targetNode); - - EntityRelation sourceRuleChainToRuleNode = new EntityRelation(); - sourceRuleChainToRuleNode.setFrom(sourceRuleChainId); - sourceRuleChainToRuleNode.setTo(targetNode.getId()); - sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE); - sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN); - relationService.saveRelation(tenantId, sourceRuleChainToRuleNode); - - EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation(); - sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId()); - sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId()); - sourceRuleNodeToTargetRuleNode.setType(relation.getType()); - sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE); - sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo()); - relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode); - - //Delete old relation - relationService.deleteRelation(tenantId, relation); - } + RuleNodeId sourceNodeId = new RuleNodeId(relation.getFrom().getId()); + RuleNode sourceNode = ruleChainService.findRuleNodeById(TenantId.SYS_TENANT_ID, sourceNodeId); + if (sourceNode == null) { + log.info("Skip processing of relation for non existing source rule node: [{}]", sourceNodeId); + relationService.deleteRelation(TenantId.SYS_TENANT_ID, relation); + continue; + } + RuleChainId sourceRuleChainId = sourceNode.getRuleChainId(); + RuleChainId targetRuleChainId = new RuleChainId(relation.getTo().getId()); + RuleChain targetRuleChain = ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, targetRuleChainId); + if (targetRuleChain == null) { + log.info("Skip processing of relation for non existing target rule chain: [{}]", targetRuleChainId); + relationService.deleteRelation(TenantId.SYS_TENANT_ID, relation); + continue; } + TenantId tenantId = targetRuleChain.getTenantId(); + RuleNode targetNode = new RuleNode(); + targetNode.setName(targetRuleChain.getName()); + targetNode.setRuleChainId(sourceRuleChainId); + targetNode.setType(TbRuleChainInputNode.class.getName()); + TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration(); + configuration.setRuleChainId(targetRuleChain.getId().toString()); + targetNode.setConfiguration(JacksonUtil.valueToTree(configuration)); + targetNode.setAdditionalInfo(relation.getAdditionalInfo()); + targetNode.setDebugMode(false); + targetNode = ruleChainService.saveRuleNode(tenantId, targetNode); + + EntityRelation sourceRuleChainToRuleNode = new EntityRelation(); + sourceRuleChainToRuleNode.setFrom(sourceRuleChainId); + sourceRuleChainToRuleNode.setTo(targetNode.getId()); + sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE); + sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN); + relationService.saveRelation(tenantId, sourceRuleChainToRuleNode); + + EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation(); + sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId()); + sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId()); + sourceRuleNodeToTargetRuleNode.setType(relation.getType()); + sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE); + sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo()); + relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode); + + //Delete old relation + relationService.deleteRelation(tenantId, relation); + updated++; } catch (Exception e) { - log.error("Unable to update Tenant", e); + log.info("Failed to update RuleNodeToRuleChainRelation: {}", relation, e); } } - }; + if (updated > 0) { + log.info("RuleNodeToRuleChainRelations: {} entities updated so far...", updated); + } + } + } catch (Exception e) { + log.error("Unable to update Tenant", e); + } + } private final PaginatedUpdater tenantsDefaultEdgeRuleChainUpdater = new PaginatedUpdater<>() { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index c0cddd9337..c175503d19 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -63,4 +63,6 @@ public interface AlarmService { PageData findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, AlarmDataQuery query, Collection orderedEntityIds); + + void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java index e6a9538e54..52fed96493 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -30,8 +30,6 @@ public interface EntityService { CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId); - void deleteEntityRelations(TenantId tenantId, EntityId entityId); - long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index 8918b7cc1f..d7fe41e8c7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -64,4 +64,6 @@ public interface AlarmDao extends Dao { void createEntityAlarmRecord(EntityAlarm entityAlarm); List findEntityAlarmRecords(TenantId tenantId, AlarmId id); + + void deleteEntityAlarmRecords(TenantId tenantId, EntityId entityId); } 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 64874eff7d..eb6d5c778e 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 @@ -46,7 +46,6 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.EntitySearchDirection; -import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; @@ -350,6 +349,11 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null); } + @Override + public void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId) { + alarmDao.deleteEntityAlarmRecords(tenantId, entityId); + } + private Alarm merge(Alarm existing, Alarm alarm) { if (alarm.getStartTs() > existing.getEndTs()) { existing.setEndTs(alarm.getStartTs()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java index 4d2a299576..970712fc19 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -18,12 +18,14 @@ package org.thingsboard.server.dao.entity; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -41,6 +43,10 @@ public abstract class AbstractEntityService { @Autowired protected RelationService relationService; + @Lazy + @Autowired + protected AlarmService alarmService; + @Autowired protected EntityViewService entityViewService; @@ -60,6 +66,8 @@ public abstract class AbstractEntityService { protected void deleteEntityRelations(TenantId tenantId, EntityId entityId) { log.trace("Executing deleteEntityRelations [{}]", entityId); relationService.deleteEntityRelations(tenantId, entityId); + log.trace("Executing deleteEntityAlarms [{}]", entityId); + alarmService.deleteEntityAlarmRelations(tenantId, entityId); } protected Optional extractConstraintViolationException(Exception t) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 7686d9ec21..06e19a7730 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -104,11 +104,6 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe @Autowired private OtaPackageService otaPackageService; - @Override - public void deleteEntityRelations(TenantId tenantId, EntityId entityId) { - super.deleteEntityRelations(tenantId, entityId); - } - @Override public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) { log.trace("Executing countEntitiesByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 1e1d0eee18..996c0801ff 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -563,10 +563,9 @@ public class BaseRelationService implements RelationService { @Override public List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) { - log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}] and limit {}", - tenantId, limit); + log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}], ruleChainType {} and limit {}", tenantId, ruleChainType, limit); validateId(tenantId, "Invalid tenant id: " + tenantId); - return relationDao.findRuleNodeToRuleChainRelations(tenantId, ruleChainType, limit); + return relationDao.findRuleNodeToRuleChainRelations(ruleChainType, limit); } protected void validate(EntityRelation relation) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index efb516af3e..85d333b04a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -61,5 +61,5 @@ public interface RelationDao { ListenableFuture deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity); - List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit); + List findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 33ef74db65..6b990a7c6c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -28,7 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; @@ -48,7 +47,6 @@ import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainImportResult; import org.thingsboard.server.common.data.rule.RuleChainMetaData; -import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java index ad67e9ba1d..852b0d2ce6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.sql.alarm; import org.springframework.data.repository.CrudRepository; +import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.dao.model.sql.EntityAlarmCompositeKey; import org.thingsboard.server.dao.model.sql.EntityAlarmEntity; @@ -26,4 +27,6 @@ public interface EntityAlarmRepository extends CrudRepository findAllByAlarmId(UUID alarmId); + @Transactional + void deleteByEntityId(UUID id); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index 73e7a39b9a..eaed0480c4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -183,4 +183,10 @@ public class JpaAlarmDao extends JpaAbstractDao implements A log.trace("[{}] Try to find entity alarm records using [{}]", tenantId, id); return DaoUtil.convertDataList(entityAlarmRepository.findAllByAlarmId(id.getId())); } + + @Override + public void deleteEntityAlarmRecords(TenantId tenantId, EntityId entityId) { + log.trace("[{}] Try to delete entity alarm records using [{}]", tenantId, entityId); + entityAlarmRepository.deleteByEntityId(entityId.getId()); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 5291da6669..4b021114f7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -199,8 +199,8 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple } @Override - public List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) { - return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(tenantId.getId(), ruleChainType, PageRequest.of(0, limit))); + public List findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit) { + return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(ruleChainType, PageRequest.of(0, limit))); } private Specification getEntityFieldsSpec(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java index 28b125ac3c..65c888f39e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java @@ -58,15 +58,9 @@ public interface RelationRepository String fromType); @Query("SELECT r FROM RelationEntity r WHERE " + - "r.fromId in (SELECT id from RuleNodeEntity where ruleChainId in " + - "(SELECT id from RuleChainEntity where tenantId = :tenantId and type = :ruleChainType ))" + - "AND r.fromType = 'RULE_NODE' " + - "AND r.toType = 'RULE_CHAIN' " + - "AND r.relationTypeGroup = 'RULE_NODE'") - List findRuleNodeToRuleChainRelations( - @Param("tenantId") UUID tenantId, - @Param("ruleChainType") RuleChainType ruleChainType, - Pageable page); + "r.relationTypeGroup = 'RULE_NODE' AND r.toType = 'RULE_CHAIN' " + + "AND r.toId in (SELECT id from RuleChainEntity where type = :ruleChainType )") + List findRuleNodeToRuleChainRelations(@Param("ruleChainType") RuleChainType ruleChainType, Pageable page); @Transactional S save(S entity); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index de27c8d554..4fc5fbaebc 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -66,7 +66,7 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( alarm_type varchar(255) NOT NULL, customer_id uuid, alarm_id uuid, - CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); From a5b747107b1d852e1344af9697cbc24991fc3caa Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 9 Dec 2021 18:46:35 +0200 Subject: [PATCH 302/303] UI: Create nested rule chain from selected region --- ...ate-nested-rulechain-dialog.component.html | 65 ++++ .../rulechain/rulechain-page.component.scss | 2 +- .../rulechain/rulechain-page.component.ts | 298 +++++++++++++++++- .../home/pages/rulechain/rulechain.module.ts | 5 +- ui-ngx/src/app/shared/models/constants.ts | 3 +- .../src/app/shared/models/rule-node.models.ts | 8 +- .../assets/locale/locale.constant-en_US.json | 1 + 7 files changed, 375 insertions(+), 7 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/pages/rulechain/create-nested-rulechain-dialog.component.html diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/create-nested-rulechain-dialog.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/create-nested-rulechain-dialog.component.html new file mode 100644 index 0000000000..a8e719dbab --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/rulechain/create-nested-rulechain-dialog.component.html @@ -0,0 +1,65 @@ + +
        + +

        rulenode.create-nested-rulechain

        + + +
        + + +
        + +
        + + rulechain.name + + + {{ 'rulechain.name-required' | translate }} + + + {{ 'rulechain.name-max-length' | translate }} + + +
        + + rulechain.description + + +
        +
        + +
        +
        + + +
        + diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss index 24b1ecc9b0..a05c80bb04 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss @@ -325,7 +325,7 @@ } .tb-rule-chain-context-menu { - min-width: 256px; + min-width: 320px; max-height: 404px; border-radius: 8px; margin-left: -20px; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index 8784716861..b240fc104b 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -54,7 +54,7 @@ import { FcRuleNode, FcRuleNodeType, getRuleNodeHelpLink, - LinkLabel, + LinkLabel, outputNodeClazz, ruleChainNodeClazz, RuleNode, RuleNodeComponentDescriptor, RuleNodeType, @@ -405,6 +405,17 @@ export class RuleChainPageComponent extends PageComponent }, ['INPUT', 'SELECT', 'TEXTAREA'], this.translate.instant('rulenode.delete-selected-objects')) ); + this.hotKeys.push( + new Hotkey('ctrl+r', (event: KeyboardEvent) => { + if (this.enableHotKeys && this.canCreateNestedRuleChain()) { + event.preventDefault(); + this.createNestedRuleChain(); + return false; + } + return true; + }, ['INPUT', 'SELECT', 'TEXTAREA'], + this.translate.instant('rulenode.create-nested-rulechain')) + ); } } @@ -684,6 +695,19 @@ export class RuleChainPageComponent extends PageComponent shortcut: 'Esc' } ); + if (this.canCreateNestedRuleChain()) { + contextInfo.menuItems.push( + { + action: () => { + this.createNestedRuleChain(); + }, + enabled: true, + value: 'rulenode.create-nested-rulechain', + icon: 'settings_ethernet', + shortcut: 'M-R' + } + ); + } contextInfo.menuItems.push( { action: () => { @@ -818,6 +842,208 @@ export class RuleChainPageComponent extends PageComponent return contextInfo; } + private canCreateNestedRuleChain(): boolean { + const selectedNodes = this.ruleChainCanvas.modelService.nodes.getSelectedNodes(); + const selectedEdges = this.ruleChainCanvas.modelService.edges.getSelectedEdges(); + if (selectedNodes.length > 1) { + const toIndexSet = new Set(); + selectedEdges.forEach((edge: FcRuleEdge) => { + const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.source); + const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination); + const fromIndex = selectedNodes.indexOf(sourceNode); + const toIndex = selectedNodes.indexOf(destNode); + if (fromIndex > -1 && toIndex > -1) { + toIndexSet.add(toIndex); + } + }); + const noInputNodes = selectedNodes.filter((node, index) => !toIndexSet.has(index)); + return noInputNodes.filter((node: FcRuleNode) => node.component.configurationDescriptor.nodeDefinition.inEnabled).length <= 1; + } + return false; + } + + private createNestedRuleChain() { + const selectedNodes = this.ruleChainCanvas.modelService.nodes.getSelectedNodes(); + const selectedEdges = this.ruleChainCanvas.modelService.edges.getSelectedEdges(); + this.dialog.open(CreateNestedRuleChainDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + ruleChainType: this.ruleChainType + } + }).afterClosed().subscribe((ruleChain) => { + if (ruleChain) { + this.ruleChainCanvas.modelService.deselectAll(); + const ruleChainMetaData: RuleChainMetaData = { + ruleChainId: ruleChain.id, + nodes: [], + connections: [] + }; + let outputEdges: FcRuleEdge[] = []; + let minX: number = null; + let maxX = 0; + let minY = null; + let maxY = 0; + + selectedNodes.forEach((node: FcRuleNode) => { + const ruleNode: RuleNode = { + type: node.component.clazz, + name: node.name, + configuration: deepClone(node.configuration), + additionalInfo: node.additionalInfo ? deepClone(node.additionalInfo) : {}, + debugMode: node.debugMode + }; + if (minX === null) { + minX = node.x; + } else { + minX = Math.min(minX, node.x); + } + if (minY === null) { + minY = node.y; + } else { + minY = Math.min(minY, node.y); + } + maxX = Math.max(maxX, node.x); + maxY = Math.max(maxY, node.y); + ruleNode.additionalInfo.layoutX = Math.round(node.x); + ruleNode.additionalInfo.layoutY = Math.round(node.y); + ruleChainMetaData.nodes.push(ruleNode); + const outputConnectors = this.ruleChainCanvas.modelService.nodes.getConnectorsByType(node, FlowchartConstants.rightConnectorType); + outputConnectors.forEach(connector => { + const nodeOutputEdges = this.ruleChainCanvas.modelService.model.edges.filter(edge => edge.source === connector.id); + const outerEdges = nodeOutputEdges.filter(edge => { + const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination); + return selectedNodes.indexOf(destNode) === -1; + }); + outputEdges = outputEdges.concat(outerEdges); + }); + }); + const toIndexSet = new Set(); + selectedEdges.forEach((edge: FcRuleEdge) => { + const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.source); + const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination); + if (sourceNode.component.type !== RuleNodeType.INPUT) { + const fromIndex = selectedNodes.indexOf(sourceNode); + const toIndex = selectedNodes.indexOf(destNode); + if (fromIndex > -1 && toIndex > -1) { + const nodeConnection = { + fromIndex, + toIndex + } as NodeConnectionInfo; + edge.labels.forEach((label) => { + const newNodeConnection = deepClone(nodeConnection); + newNodeConnection.type = label; + ruleChainMetaData.connections.push(newNodeConnection); + }); + toIndexSet.add(toIndex); + } + } + }); + const noInputNodes = selectedNodes.filter((node, index) => !toIndexSet.has(index)); + const possibleInputNodes = noInputNodes.filter((node: FcRuleNode) => + node.component.configurationDescriptor.nodeDefinition.inEnabled); + let inputEdges: FcRuleEdge[] = []; + if (possibleInputNodes.length) { + const firstNode = possibleInputNodes[0]; + const inputConnectors = this.ruleChainCanvas.modelService.nodes + .getConnectorsByType(firstNode, FlowchartConstants.leftConnectorType); + if (inputConnectors.length) { + const inputConnector = inputConnectors[0]; + const nodeInputEdges = this.ruleChainCanvas.modelService.model.edges.filter(edge => edge.destination === inputConnector.id); + inputEdges = inputEdges.concat(nodeInputEdges); + } + ruleChainMetaData.firstNodeIndex = selectedNodes.indexOf(firstNode); + } + outputEdges.forEach((outputEdge) => { + const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(outputEdge.source); + const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(outputEdge.destination); + const outputNode: RuleNode = { + type: outputNodeClazz, + name: outputEdge.label, + configuration: {}, + additionalInfo: {}, + debugMode: false + }; + outputNode.additionalInfo.layoutX = Math.round(destNode.x); + outputNode.additionalInfo.layoutY = Math.round(destNode.y); + ruleChainMetaData.nodes.push(outputNode); + const fromIndex = selectedNodes.indexOf(sourceNode); + const toIndex = ruleChainMetaData.nodes.length - 1; + const nodeConnection = { + fromIndex, + toIndex + } as NodeConnectionInfo; + outputEdge.labels.forEach((label) => { + const newNodeConnection = deepClone(nodeConnection); + newNodeConnection.type = label; + ruleChainMetaData.connections.push(newNodeConnection); + }); + }); + const deltaX = Math.round(minX - 375); + const deltaY = Math.round(minY - 150); + ruleChainMetaData.nodes.forEach((node) => { + node.additionalInfo.layoutX -= deltaX; + node.additionalInfo.layoutY -= deltaY; + }); + this.ruleChainService.saveRuleChainMetadata(ruleChainMetaData).subscribe(() => { + const component = this.ruleChainService.getRuleNodeComponentByClazz(this.ruleChainType, ruleChainNodeClazz); + const descriptor = ruleNodeTypeDescriptors.get(component.type); + let icon = descriptor.icon; + let iconUrl = null; + if (component.configurationDescriptor.nodeDefinition.icon) { + icon = component.configurationDescriptor.nodeDefinition.icon; + } + if (component.configurationDescriptor.nodeDefinition.iconUrl) { + iconUrl = component.configurationDescriptor.nodeDefinition.iconUrl; + } + const ruleChainNodeX = (minX + maxX) / 2; + const ruleChainNodeY = (minY + maxY) / 2; + const ruleChainInputId = (this.nextConnectorID++) + ''; + const ruleChainOutputId = (this.nextConnectorID++) + ''; + const ruleChainNode: FcRuleNode = { + name: ruleChain.name, + component, + id: 'rule-chain-node-' + this.nextNodeID++, + configuration: { + ruleChainId: ruleChain.id.id + }, + debugMode: false, + x: Math.round(ruleChainNodeX), + y: Math.round(ruleChainNodeY), + nodeClass: descriptor.nodeClass, + icon, + iconUrl, + ruleChainType: this.ruleChainType, + connectors: [ + { + type: FlowchartConstants.leftConnectorType, + id: ruleChainInputId + }, + { + type: FlowchartConstants.rightConnectorType, + id: ruleChainOutputId + } + ] + }; + this.ruleChainModel.nodes.push(ruleChainNode); + inputEdges.forEach((inputEdge) => { + inputEdge.destination = ruleChainInputId; + }); + outputEdges.forEach((outputEdge) => { + outputEdge.source = ruleChainOutputId; + outputEdge.labels = [outputEdge.label]; + }); + selectedNodes.forEach((node) => { + this.ruleChainCanvas.modelService.nodes.delete(node); + }); + this.onModelChanged(); + this.updateRuleNodesHighlight(); + }); + } + }); + } + onModelChanged() { this.isDirtyValue = true; this.validate(); @@ -1498,3 +1724,73 @@ export class AddRuleNodeDialogComponent extends DialogComponent + implements OnInit, ErrorStateMatcher { + + createNestedRuleChainFormGroup: FormGroup; + + submitted = false; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: CreateNestedRuleChainDialogData, + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, + private fb: FormBuilder, + private ruleChainService: RuleChainService, + public dialogRef: MatDialogRef) { + super(store, router, dialogRef); + + } + + ngOnInit(): void { + this.createNestedRuleChainFormGroup = this.fb.group( + { + name: ['', [Validators.required, Validators.maxLength(255)]], + additionalInfo: this.fb.group( + { + description: [''], + } + ) + } + ); + } + + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); + const customErrorState = !!(control && control.invalid && this.submitted); + return originalErrorState || customErrorState; + } + + cancel(): void { + this.dialogRef.close(null); + } + + add(): void { + this.submitted = true; + const ruleChain = { + name: this.createNestedRuleChainFormGroup.get('name').value, + debugMode: false, + type: this.data.ruleChainType, + additionalInfo: { + description: this.createNestedRuleChainFormGroup.get('additionalInfo').get('description').value + } + } as RuleChain; + this.ruleChainService.saveRuleChain(ruleChain).subscribe( + (savedRuleChain) => { + this.dialogRef.close(savedRuleChain); + } + ); + } +} + diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts index 95bb4bf3f8..73df594f89 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts @@ -23,7 +23,7 @@ import { HomeComponentsModule } from '@modules/home/components/home-components.m import { RuleChainTabsComponent } from '@home/pages/rulechain/rulechain-tabs.component'; import { AddRuleNodeDialogComponent, - AddRuleNodeLinkDialogComponent, + AddRuleNodeLinkDialogComponent, CreateNestedRuleChainDialogComponent, RuleChainPageComponent } from './rulechain-page.component'; import { RuleNodeComponent } from '@home/pages/rulechain/rulenode.component'; @@ -44,7 +44,8 @@ import { RuleNodeConfigComponent } from './rule-node-config.component'; LinkLabelsComponent, RuleNodeLinkComponent, AddRuleNodeLinkDialogComponent, - AddRuleNodeDialogComponent + AddRuleNodeDialogComponent, + CreateNestedRuleChainDialogComponent ], providers: [ { diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index b30ed084ab..9bf120f8b7 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -100,7 +100,8 @@ export const HelpLinks = { ruleNodeSaveAttributes: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#save-attributes-node', ruleNodeSaveTimeseries: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#save-timeseries-node', ruleNodeSaveToCustomTable: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#save-to-custom-table', - ruleNodeRuleChain: helpBaseUrl + '/docs/user-guide/ui/rule-chains/', + ruleNodeRuleChain: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/flow-nodes/#rule-chain-node', + ruleNodeOutputNode: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/flow-nodes/#output-node', ruleNodeAwsSns: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#aws-sns-node', ruleNodeAwsSqs: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#aws-sqs-node', ruleNodeKafka: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#kafka-node', diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index ce2563826f..f30574ce7b 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -394,6 +394,9 @@ export const messageTypeNames = new Map( ] ); +export const ruleChainNodeClazz = 'org.thingsboard.rule.engine.flow.TbRuleChainInputNode'; +export const outputNodeClazz = 'org.thingsboard.rule.engine.flow.TbRuleChainOutputNode'; + const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.filter.TbCheckRelationNode': 'ruleNodeCheckRelation', 'org.thingsboard.rule.engine.filter.TbCheckMessageNode': 'ruleNodeCheckExistenceFields', @@ -431,7 +434,6 @@ const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode': 'ruleNodeSaveAttributes', 'org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode': 'ruleNodeSaveTimeseries', 'org.thingsboard.rule.engine.action.TbSaveToCustomCassandraTableNode': 'ruleNodeSaveToCustomTable', - 'tb.internal.RuleChain': 'ruleNodeRuleChain', 'org.thingsboard.rule.engine.aws.sns.TbSnsNode': 'ruleNodeAwsSns', 'org.thingsboard.rule.engine.aws.sqs.TbSqsNode': 'ruleNodeAwsSqs', 'org.thingsboard.rule.engine.kafka.TbKafkaNode': 'ruleNodeKafka', @@ -442,7 +444,9 @@ const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.mail.TbSendEmailNode': 'ruleNodeSendEmail', 'org.thingsboard.rule.engine.sms.TbSendSmsNode': 'ruleNodeSendSms', 'org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode': 'ruleNodePushToCloud', - 'org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode': 'ruleNodePushToEdge' + 'org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode': 'ruleNodePushToEdge', + 'org.thingsboard.rule.engine.flow.TbRuleChainInputNode': 'ruleNodeRuleChain', + 'org.thingsboard.rule.engine.flow.TbRuleChainOutputNode': 'ruleNodeOutputNode', }; export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): string { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 05e2039633..3982bfedda 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2587,6 +2587,7 @@ "deselect-all-objects": "Deselect all nodes and connections", "delete-selected-objects": "Delete selected nodes and connections", "delete-selected": "Delete selected", + "create-nested-rulechain": "Create nested rule chain", "select-all": "Select all", "copy-selected": "Copy selected", "deselect-all": "Deselect all", From 6d97d9466fc4463a4117e38ac93ece7c7e066bbf Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 9 Dec 2021 18:54:52 +0200 Subject: [PATCH 303/303] Update rule nodes UI --- .../resources/public/static/rulenode/rulenode-core-config.js | 3 +++ 1 file changed, 3 insertions(+) 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 54fbc87f07..ae61853e4b 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 @@ -204,6 +204,7 @@ var EntityDetailsField; EntityDetailsField["TITLE"] = "TITLE"; EntityDetailsField["COUNTRY"] = "COUNTRY"; EntityDetailsField["STATE"] = "STATE"; + EntityDetailsField["CITY"] = "CITY"; EntityDetailsField["ZIP"] = "ZIP"; EntityDetailsField["ADDRESS"] = "ADDRESS"; EntityDetailsField["ADDRESS2"] = "ADDRESS2"; @@ -215,6 +216,7 @@ const entityDetailsTranslations = new Map([ [EntityDetailsField.TITLE, 'tb.rulenode.entity-details-title'], [EntityDetailsField.COUNTRY, 'tb.rulenode.entity-details-country'], [EntityDetailsField.STATE, 'tb.rulenode.entity-details-state'], + [EntityDetailsField.CITY, 'tb.rulenode.entity-details-city'], [EntityDetailsField.ZIP, 'tb.rulenode.entity-details-zip'], [EntityDetailsField.ADDRESS, 'tb.rulenode.entity-details-address'], [EntityDetailsField.ADDRESS2, 'tb.rulenode.entity-details-address2'], @@ -4105,6 +4107,7 @@ function addRuleNodeCoreLocaleEnglish(translate) { 'entity-details-title': 'Title', 'entity-details-country': 'Country', 'entity-details-state': 'State', + 'entity-details-city': 'City', 'entity-details-zip': 'Zip', 'entity-details-address': 'Address', 'entity-details-address2': 'Address2',